zoukankan      html  css  js  c++  java
  • bzoj4037: [HAOI2015]数字串拆分(动态规划+矩阵)

    www.cnblogs.com/shaokele/


    bzoj4037: [HAOI2015]数字串拆分(动态规划+矩阵)##

      Time Limit: 10 Sec
      Memory Limit: 256 MB

    Description###

      你有一个长度为n的数字串。定义f(S)为将S拆分成若干个1~m的数的和的方案数,比如m=2时,f(4)=5,分别为4=1+1+1+1你可以将这个数字串分割成若干个数字(允许前导0),将他们加起来,求f,并求和。比如g(123)=f(1+2+3)+f(1+23)+f(12+3)+f(123)。已知字符串和m后求答案对998244353(7×17×223+1,一个质数)取模后的值。
      

    Input###

      第一行输入一个字符串,第二行输入m
      

    Output###

      仅输出一个数表示答案
      

    Sample Input 1###

      123
      3
     

    Sample Output 1###

      394608467
      

    HINT###

       对于100%的数据,字符串长度不超过500,m<=5
      

    题目地址:  bzoj4037: [HAOI2015]数字串拆分

    题目大意:

      定义 (f(x)) 为把 (x) 有序拆分成若干 (1)(m) 之间数的方案数。
      例如当 m=2 时,4=1+1+1+1=1+1+2=1+2+1=2+1+1=2+2,因此 (f(x)=5)
      给定一个 n 位数字串 (S) 将这个数字串分割成若干数字(允许前导零),将它们加起来,求 (f) ,再对所有方案求和并输出。
      例如 123 的答案 g(123)=f(1+2+3)+f(12+3)+f(1+23)+f(123)。

    题解:

      $$ f(x)=sum_{i=1}^{m} f(x-i)$$
      发现 m 非常小,可以用矩阵乘法快速求出 f(x) **
      
    对于最终答案,我们考虑 dp ,g(i) 表示前 i 位的答案,由于 f 中还有加法,我们不能转移。**
      假设矩阵为 A ,f(x) 和 (A^x) 是等价的。 (f(a+b)=A^{a+b}=A^aA^b) ,也就是说我们可以化加为乘
      在求 g 时,保留矩阵形式,那么就有转移:
      $$ g(i)=sum_{j=1}{i-1}g(j)*A{S[j+1,i]}。$$
      


    AC代码

    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N=1005,Mod=998244353;
    int n,m,ch[N];
    char st[N];
    struct matrix{
    	int A[6][6];
    }f[15][N],g[N],tran;
    matrix operator *(matrix a,matrix b){
    	matrix res;
    	memset(res.A,0,sizeof(res.A));
    	for(int i=1;i<=m;i++)
    		for(int k=1;k<=m;k++)
    			if(a.A[i][k])
    				for(int j=1;j<=m;j++){
    					res.A[i][j]=(res.A[i][j]+(ll)a.A[i][k]*b.A[k][j]%Mod);
    					if(res.A[i][j]>=Mod)res.A[i][j]-=Mod;
    				}
    	return res;
    }
    matrix operator +(matrix a,matrix b){
    	for(int i=1;i<=m;i++)
    		for(int j=1;j<=m;j++){
    			a.A[i][j]+=b.A[i][j];
    			if(a.A[i][j]>=Mod)a.A[i][j]-=Mod;
    		}
    	return a;
    }
    matrix fast_pow(matrix x,int e){
    	matrix res=x;
    	while(e){
    		if(e&1)res=res*x;
    		x=x*x;
    		e>>=1;
    	}
    	return res;
    }
    int main(){
    	scanf("%s",st+1);
    	n=strlen(st+1);
    	scanf("%d",&m);
    	for(int i=1;i<=n;i++)ch[i]=st[i]-'0';
    	for(int i=1;i<=m;i++){
    		tran.A[i][m]=f[0][1].A[i][i]=1;
    		if(i>1)tran.A[i][i-1]=1;
    	}
    	for(int i=1;i<=9;i++){
    		f[i][1]=f[i-1][1]*tran;
    		for(int j=2;j<=n;j++)
    			f[i][j]=fast_pow(f[i][j-1],9);
    	}
    	g[0].A[1][m]=1;matrix tmp;
    	for(int i=1;i<=n;i++){
    		tmp=f[ch[i]][1];
    		for(int j=i-1;j>=0;j--){
    			g[i]=g[i]+g[j]*tmp;
    			if (j && ch[j])tmp=tmp*f[ch[j]][i-j+1];
    		}
    	}
    	printf("%d
    ",g[n].A[1][m]);
    	return 0;
    }
    
  • 相关阅读:
    .net core 3.1 使用Redis缓存
    JavaSE 高级 第11节 缓冲输入输出字节流
    JavaSE 高级 第10节 字节数组输出流ByteArrayOutputStream
    JavaSE 高级 第09节 字节数组输入流ByteArrayInputStream
    JavaSE 高级 第08节 文件输出流FileOutputStream
    JavaSE 高级 第07节 文件输入流FileInputStream
    JavaSE 高级 第06节 初识I、O流
    JavaSE 高级 第05节 日期类与格式化
    JavaSE 高级 第04节 StringBuffer类
    JavaSE 高级 第03节 Math类与猜数字游戏
  • 原文地址:https://www.cnblogs.com/shaokele/p/9310309.html
Copyright © 2011-2022 走看看