用N个不同的字符(编号1 - N),组成一个字符串,有如下要求:
(1) 对于编号为i的字符,如果2 * i > n,则该字符可以作为结尾字符。如果不作为结尾字符而是中间的字符,则该字符后面可以接任意字符。
(2) 对于编号为i的字符,如果2 * i <= n,则该字符不可以作为结尾字符。作为中间字符,那么后面接的字符编号一定要 >= 2 * i。
问有多少长度为M且符合条件的字符串,由于数据很大,只需要输出该数Mod 10^9 + 7的结果。
例如:N = 2,M = 3。则abb, bab, bbb是符合条件的字符串,剩下的均为不符合条件的字符串。
Input
输入2个数,N, M中间用空格分割,N为不同字符的数量,M为字符串的长度。(2 <= N <= 10^6, 2 <= M <= 10^18)
Output
输出符合条件的字符串的数量。由于数据很大,只需要输出该数Mod 10^9 + 7的结果。
想半天不会做然后跑去瞄题解。。
首先,一个合法的字符串显然是由若干个合法的“链”组成的。
链的定义就是:从一个字母开始连,后面每个字母编号必须大于等于前一个的2倍,这样尽可能的连接下去。
所谓尽可能连接下去的意思是,链的最后一个字母编号i必须满足2 * i > n ,这样后面不能接东西了,并且只有这样的链才合法。
对于每个合法字符串,划分成合法链的方法是唯一的。
那么因为n不大,所以链的最大长度也很小...
设f[i][j]表示长度为i的链,链末尾编号为j的方案数。这个可以直接算出来,也就可以得到g[i]表示长度为i的链的所有方案数。
设ans[i]表示长度为i的合法字符串数,那么ans[i]=sum{ ans[i-x]*g[x] },1<=x<=链的最大长度。这个直接矩乘。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 #include<cstdlib> 8 #define ll long long 9 #define ull unsigned long long 10 #define ui unsigned int 11 //#define d double 12 #define ld long double 13 const int maxn=1000233,modd=1000000007; 14 struct mat{int mp[22][22];}a,c; 15 int f[2][maxn],af[2][maxn]; 16 int i,j,k,n,m,n1,len; 17 18 int ra,fh;char rx; 19 inline int read(){ 20 rx=getchar(),ra=0,fh=1; 21 while(rx<'0'&&rx!='-')rx=getchar(); 22 if(rx=='-')fh=-1,rx=getchar(); 23 while(rx>='0')ra=ra*10+rx-48,rx=getchar();return ra*fh; 24 } 25 26 inline void MOD(int &x){if(x>=modd)x-=modd;} 27 28 mat operator *(mat a,mat b){ 29 mat c;register int i,j,k; 30 for(i=1;i<=len;i++)for(j=1;j<=len;j++)for(c.mp[i][j]=0,k=1;k<=len;k++) 31 c.mp[i][j]=(c.mp[i][j]+1ll*a.mp[i][k]*b.mp[k][j])%modd; 32 return c; 33 } 34 int main(){ll m; 35 n=read(),scanf("%lld",&m); 36 for(i=1;(1<<i)<=n;i++);len=i,n1=n>>1; 37 38 for(i=n;i;i--)f[0][i]=i>n1,af[0][i]=af[0][i+1]+f[0][i]; 39 a.mp[1][1]=af[0][1];//printf(" %d ",af[0][1]); 40 41 bool now=1,pre=0;int premx=n; 42 for(i=2;i<=len;i++,std::swap(now,pre)){ 43 premx>>=1,af[now][premx+1]=0; 44 for(j=premx;j;j--)MOD(af[now][j]=af[now][j+1]+(f[now][j]=af[pre][j<<1]));//,printf("%d %d f:%d ",i,j,f[now][j]); 45 a.mp[1][i]=af[now][1]; 46 } 47 for(i=2;i<=len;i++)a.mp[i][i-1]=1; 48 for(i=1;i<=len;i++)c.mp[i][i]=1; 49 50 while(m){ 51 if(m&1)c=c*a; 52 if(m>>=1)a=a*a; 53 } 54 printf("%d ",c.mp[1][1]); 55 }