[51nod1197]字符串的数量 V2

  用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 }
View Code
原文地址:https://www.cnblogs.com/czllgzmzl/p/5949207.html