BNUOJ 34985 北京邀请赛 E题 Elegant String dp & 矩阵

6 篇文章 0 订阅
3 篇文章 0 订阅


题目链接 : Click here




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

Source



思路。。

如果认真想条件的话。。 其实发现他就是一个DP。。

只不过N太大。。需要用矩阵来算。。

dp[i][j] ,  i 表示字符串长度。 j 表示与当前数不同的个数。。

则有  dp[i][j] = dp[i-1][j-1] * (k-j+1) +  dp[i-1][j] + dp[i-1][j] .... + dp[i-1][k-1];

 

用代码写出就是。

#include <bits/stdc++.h>
using namespace std;

int dp[100][100]={0};
const int MOD = 20140518;
int n,k; 
int main(){
	while(scanf("%d %d",&n,&k)!=EOF){
		memset(dp,0,sizeof(dp));
		dp[1][0]=k+1;
		for(int i = 1;i <= n;i++)
			for(int j = 0;j < k;j++){
				if(j>0)
					dp[i][j] = (dp[i][j] + dp[i-1][j-1]*(k-j+1)) % MOD;
				for(int z = j; z < k;z++){
					dp[i][j] = (dp[i][j] + dp[i-1][z]) % MOD;
				}
				//printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
			}
		//printf("\n");
		int sum = 0;
		for(int i = 0;i < k;i++){
			sum = (sum + dp[n][i]) % MOD;
			//printf("dp[%d][%d]=%d\n",n,i,dp[n][i]);
		}
		printf("%d\n",sum);
	}
	return 0;
}

但由于N太大。。用矩阵方法写就是

#include <bits/stdc++.h>
using namespace std;

/*
origin matrix
k+1 0 0 0 0 0 0 0   there is k-1 zero

right matrix
there is k row k col
1  k  0   0   0
1  1  k-1 0   0
1  1  1   k-2 0
1  1  1   0   k-3
1  1  1   0   0
1  1  1   0   0
*/
const int MOD = 20140518;
struct Matrix{
	int mat[12][12];
	int n;
	void init(int _n){
		memset(mat,0,sizeof(mat));
		n = _n;
	}
	Matrix operator *(const Matrix &b)const
    {
        Matrix ret;
        ret.n = n;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
            {
                ret.mat[i][j] = 0;
                for(int k = 0;k < n;k++)
                {
                    ret.mat[i][j] += (long long)mat[i][k]*b.mat[k][j]%MOD;
                    if(ret.mat[i][j] >= MOD)
                        ret.mat[i][j] -= MOD;
                }
            }
        return ret;
    }
	void print(){
		for(int i = 0;i < n;i++){
			for(int j = 0;j < n;j++)
				printf("%d  ",mat[i][j]);
			printf("\n");
		}
	}
};
Matrix pow_M(Matrix a,long long n)
{
    Matrix ret;
    ret.init(a.n);
    for(int i = 0;i < a.n;i++)
        ret.mat[i][i] = 1;
    Matrix tmp = a;
    while(n)
    {
        if(n&1)ret = ret*tmp;
        tmp = tmp*tmp;
        n >>= 1;
    }
    return ret;
}
long long n;
int k;
int main(){
	int cas,tt=0;
	scanf("%d",&cas);
	while(cas--){
		cin >> n >> k;
		//printf("k=%d\n",k);
		Matrix left,right; left.init(k),right.init(k);
		left.mat[0][0] = k+1;
		for(int i=0;i<k;i++)
			for(int j=i;j<k;j++){
				right.mat[j][i] = 1;
			}	
		for(int i=1;i<k;i++)
			right.mat[i-1][i] = k-i+1;
		//right.print();

		right = pow_M(right,n-1);
		left = left * right;
		long long ans = 0;
		for(int i = 0;i < k;i++){
			ans += left.mat[0][i];
			ans %= MOD;
		}
		printf("Case #%d: %d\n",++tt,(int)ans);
		
	}
	return 0;
}

已解决。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值