• [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
  • 相关阅读:
    POJ1985 树的直径(BFS
    POJ2186 强连通分量+缩点
    AIM Tech Round 5C. Rectangles 思维
    POJ2553 汇点个数(强连通分量
    hdu6370 并查集+dfs
    UVALive 7037:The Problem Needs 3D Arrays(最大密度子图)
    POJ 3155:Hard Life(最大密度子图)
    HDU 5527:Too Rich(DFS+贪心)***
    HDU 5534:Partial Tree(完全背包)***
    Wannafly挑战赛1:Treepath(DFS统计)
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5949207.html
Copyright © 2020-2023  润新知