大致题意: 规定一个序列是合法序列当且仅当它满足:①每个元素都是正整数且不能超过一个定值(M)。②相邻两个元素的差的绝对值必须是(1)。③第一个元素必须是(1)。求有多少个长度不超过(N)的本质不同的合法序列。(此处本质不同定义为,至少存在一个元素,在两个序列中出现次数不一样)
前言
我觉得我完蛋了,不光文化课做题总是看错题目,现在连做信息题都看漏了题目。
我居然没有看到这道题中关于本质不同的特殊定义,结果去推坐标系走路的式子推了半天......
思路
考虑对于若干本质相同的序列,如果我们设最大值为(Mx),则我们可以给它一个唯一表示法,形如:
1 (2 1) (2 1) ... (2 1) 2 (3 2) (3 2) ... (Mx Mx-1) Mx
1 (2 1) (2 1) ... (2 1) 2 (3 2) (3 2) ... (Mx Mx-1) Mx Mx-1 (Mx≠1)
也就可以看作是在序列(1,2,...,Mx)中插入若干对数字,显然可以用隔板法计算方案数。
注意长度是不超过(N),所以我们把剩余(N-Mx)个元素(第二种情况下是(N-Mx-1)个元素)划分成(Mx)组(每组个数都必须是偶数,因为要成对)。
前(Mx-1)组中第(i)组表示把这组元素放在(i)和(i+1)之间,第(Mx)组表示不放入序列中,这样就不重不漏了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 2000000
#define C(n,m) (1LL*Fac[n]*IFac[m]%X*IFac[(n)-(m)]%X)//组合数
#define S(x,y) C((x)+(y)-1,(y)-1)//隔板法,计算把x个元素分成y组的方案数
#define X 1000000007
using namespace std;
int n,m,Fac[N+5],IFac[N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
RI i,ans=0;scanf("%d%d",&n,&m),m>n&&(m=n);//将m向n取min
for(Fac[0]=i=1;i<=n;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理
for(IFac[n]=Qpow(Fac[n],X-2),i=n-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;//预处理
for(i=1;i<=m;++i) ans=(S(n-i>>1,i)+ans)%X,i^1&&(ans=(S(n-i-1>>1,i)+ans)%X);//枚举最大值计算两种方案,个数折半表示每两个元素成一对
return printf("%d",ans),0;
}