CF621E - Wet Shark and Blocks

来源:互联网 发布:javbus新域名2017 编辑:程序博客网 时间:2024/06/10 15:16

题目大意:给你b个格子,每个格子有n个数(1到9),你顺序从b个格子中各取一个数,依次排列好,组成一个b位数,求使得这个b位数%x余k的方案数(同一格子内相同的数字算不同方案)。

DP题,状态f[i][j]表示前i个格子取出的数%x余j的方案数。f[i][j]到f[i+1][m]转移条件是(j*10+q)%x==m,q为第i+1个格子选的数。化简之后变成F[i]*A[]=F[i+1],F和A为矩阵,这个题就变成了矩阵乘法,然后由于b太大,用快速幂优化,最后输出余k的答案即可。

难点在于A矩阵的构造,想不通的可以看一下我代码。。。虽然丑但是可读性应该是还阔以的。

快速幂一定要写非递归的。。。不然一万的long long会爆栈。。。mod注意点就好。

第一次做出来e题,也是有点小兴奋。

#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>using namespace std;int n,b,k,x;int a[55000];int bb[110];long long modd;struct MATRIX{long long m[110][110];MATRIX friend operator*(MATRIX a,MATRIX b){MATRIX c;memset(c.m,0,sizeof(c));for(int i=0;i<x;i++){for(int j=0;j<x;j++){for(int k=0;k<x;k++){c.m[i][j]+=(a.m[i][k]*b.m[k][j]);c.m[i][j]%=modd;}}}return c;}}q,ans,c,dui[110];void PR(MATRIX a){printf("\n");for(int i=0;i<x;i++){for(int j=0;j<x;j++)printf("%d ",a.m[i][j]);printf("\n");}printf("\n");}int main(){modd=1000000000+7;scanf("%d%d%d%d",&n,&b,&k,&x);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)bb[a[i]%x]++;for(int i=0;i<x;i++){for(int j=0;j<x;j++){q.m[i][(i*10+j)%x]=bb[j%x];q.m[i][(i*10+j)%x]%=modd;}}//PR(q);//q=KUAISUMI(q,b-1);int tail=1;int w=b-1;dui[1]=q;while(w!=1&&w!=0){if(w&1){tail++;dui[tail]=dui[tail-1]*dui[tail-1];}else{dui[tail]=dui[tail]*dui[tail];}w>>=1;}while(tail!=1){dui[tail-1]=dui[tail-1]*dui[tail];tail--;}q=dui[1];for(int i=0;i<x;i++)ans.m[0][i]=bb[i];//PR(ans);if(b!=1)ans=ans*q;cout<<ans.m[0][k]<<endl;return 0;}//f[i][j][k] 前i个箱子中,第i个箱子拿第j个数余k的数量 //j<=1..n f[i][k*10+a[j]]+=f[i-1][k]//f[i][0..x-1]=f[i-1][0..x-1]*A[0..x-1][0..x-1]


0 0