bnuoj 34985 Elegant String dp+矩阵快速幂

来源:互联网 发布:最强nba球员数据对比 编辑:程序博客网 时间:2024/05/29 12:30

题目链接


题意:

定义了一个优雅的串:任意子串都不是0~k的一个组合,问长度为n的优雅串有多少个?结果对20140518取余 T<=400 1<=n<=1e18 1<=k<=9


思路:

dp+矩阵优化的套路很明显,关键难在递推方程的推导,然后构造矩阵,剩下的就很简单.


/* 我们定义dp[i][j]为长度为i,尾部j个字母均不相同的字符串的数目。 那么我们很容易推出dp[i][j]的递推公式了: dp[i][j]=dp[i-1][j-1]*(k-j+2)+dp[i-1][j]+……+dp[i-1][k]; 这是什么意思呢? 首先我们知道,dp[i]和dp[i-1]只差一个字母,假设我们在dp[i-1]后面加上一个字母,这个 字母可以是和dp[i-1]尾部几个不同的字母中的一个相同,也可以不同(例:假如dp[i-1]=……0123, k=7,这是我们为了构成dp[i],我们可以在尾部加上4、5、6、7,或者0、1、2、3) 大家会发现如果是4、5、6、7,那么dp[i-1][j-1]就变成了dp[i][j](看定义), 如果是0、1、2、3,那么dp[i-1][j-1]就会相应变成dp[i][j],dp[i][j-1],dp[i][j-2],dp[i][j-3], 综上我们为了构成dp[i][j],就可以使用dp[i-1][j-1]---dp[i-1][k]来构造。  */ #include <iostream>  #include <cstdio>  #include <cstring>  using namespace std;  typedef long long ll;  const long long mod=20140518;    struct mat  {      ll t[10][10];      void set()      {          memset(t,0,sizeof(t));      }  } a,b;    mat multiple(mat a,mat b,ll n,ll p)  {      ll i,j,k;      mat temp;      temp.set();      for(i=0; i<n; i++)          for(j=0; j<n; j++)          {              if(a.t[i][j]!=0)                  for(k=0; k<n; k++)                      temp.t[i][k]=(temp.t[i][k]+a.t[i][j]*b.t[j][k])%p;          }      return temp;  }    mat quick_mod(mat b,ll n,ll m,ll p)  {      mat t;      t.set();      for(ll i=0; i<n; i++) t.t[i][i]=1;      while(m)      {          if(m&1)          {              t=multiple(t,b,n,p);          }          m>>=1;          b=multiple(b,b,n,p);      }      return t;  }    void init(ll k)  {      b.set();      for(ll i=0; i<k; i++)          b.t[i][0]=1;      for(ll i=1; i<k; i++)      {          for(ll j=i-1; j<k; j++)              if(j==i-1)                  b.t[j][i]=k-i+1;              else b.t[j][i]=1;      }      /*       for(int i=0;i<k;i++)       {           for(int j=0;j<k;j++)             printf("%lld ",b.t[i][j]);           puts("");       }      */  }      int main()  {      int cas;      ll n;      ll k;      scanf("%d",&cas);      for(int ca=1; ca<=cas; ca++)      {          scanf("%lld%lld",&n,&k);          init(k);          a=quick_mod(b,k,n-1,mod);          ll ans=0;          for(ll i=0; i<k; i++)          {              ans=(ans+(k+1)*a.t[0][i])%mod;  //初始每个位置有(k+1)选法        }          printf("Case #%d: %lld\n",ca,ans);      }      return 0;  }   



原创粉丝点击