2014 ACM-ICPC Beijing Invitational Programming Contest E



Elegant String

We define a kind of strings as elegant string: among all the substrings of an elegant string, none of them is a permutation of "0, 1,…, k".
Let function(n, k) be the number of elegant strings of length n which only contains digits from 0 to k (inclusive). Please calculate function(n, k).
 

Input

Input starts with an integer T (T ≤ 400), denoting the number of test cases.
 
Each case contains two integers, n and k. n (1 ≤ n ≤ 10 18) represents the length of the strings, and k (1 ≤ k ≤ 9) represents the biggest digit in the string.
 

Output

For each case, first output the case number as " Case #x: ", and x is the case number. Then output function(n, k) mod 20140518 in this case. 
 

Sample Input

2
1 1
7 6

Sample Output

Case #1: 2
Case #2: 818503


用F[j][i]表示结尾长度为j的有i个连续的不同的数字的种数(只有F[j][k+1]表示的长度为j的字符串中非法的有F[j][k+1]种);
1).F[j][k+1]=F[j-1][k]+F[j-1][k+1]*(k+1).
2).1<i<=k: F[j][i]=sigma(F[j-1][r])(i<=r<=k) + F[j-1][i-1]*(k+1-(i-1));
3).i==1:F[j][1]=sigma(F[j-1][r])(1<=r<=k)

参考  Zhuhuangjian的专栏

typedef  long long LL ;
const    LL  mod = 20140518 ;

int       n  ;
struct   Mat{
         LL x[11][11] ;
         Mat(){ memset(x , 0 , sizeof(x)) ; }
         Mat(int){
                memset(x , 0 , sizeof(x)) ;
                for(int i = 1 ; i <= n ; i++) x[i][i] = 1 ;
         }
};

Mat operator * (Mat A  , Mat B){
     Mat s ;
     for(int  i = 1 ; i <= n ; i++){
          for(int j = 1 ; j <= n ; j++){
               if(A.x[i][j] == 0) continue ;
               for(int k = 1 ; k <= n ; k++){
                    s.x[i][k] = (s.x[i][k] + A.x[i][j] * B.x[j][k] % mod) % mod  ;
               }
          }
     }
     return s ;
}

Mat   operator ^ (Mat x , LL y){
      Mat s(1) ;
      for(;y;y>>=1){
           if(y&1) s = s * x ;
           x = x * x ;
      }
      return s  ;
}

Mat   getA(int k){
      n = k + 1 ;
      Mat A ; int i , j ;
      for(i = 1 ; i <= k ; i++) A.x[1][i] = 1 ;
      for(i = 2 ; i <= k ; i++){
           for(j = i ; j <= k ; j++) A.x[i][j] = 1 ;
           A.x[i][i-1] = (k+1) - (i-1) ;
      }
      A.x[k+1][k] = 1 , A.x[k+1][k+1] = k+1 ;
      return A ;
}

LL    Pow(LL x , LL y){
      LL s = 1 ;
      for(;y;y>>=1){
          if(y&1){ s *= x ;  s %= mod ; }
          x *= x ; x %= mod ;
      }
      return s ;
}

int   main(){
      int t , T = 1  , k ;
      LL  N , s ;
      cin>>t  ;
      while(t--){
           scanf("%lld%d" ,&N , &k) ;
           printf("Case #%d: " , T++) ;
           if(N == 1){ printf("%d\n" , k+1) ; continue ;}
           s = Pow(LL(k+1) , N) ;
           Mat A = getA(k) ;
           A = A ^ (N-1) ;
           s -= (A.x[k+1][1] * (LL)(k+1)) % mod ;
           s = (s + mod) % mod ;
           printf("%lld\n" , s) ;
      }
      return 0 ;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值