感觉自己太弱了……cf div2都只能做3题哈哈,下半年区域赛没有着落~
这题看到就感觉变量很多,可能是因为前段时间做了数论的题,看到这题想用剩余定理;
想通过找规律,发现循环节,每变化一次对模数的变化,来进行统计,问题在于1.可能没有规律2.可能还是要一种情况一种情况算
看了答案之后发现,可以用矩阵优化的DP,真是厉害,因为比如前n个模x的值已知,*10之后再加一个数,模x就也好算了
要充分利用x比较小的条件,利用模运算……(当时自己为什么没想到)
代码参考了http://blog.youkuaiyun.com/jzhang1/article/details/50628041#
矩阵快速幂的模板还是很棒的
如果想到了dp的方法,F[i][(c * 10 + num) % x] += F[i - 1][c]
想用矩阵快速幂来求得话,想要使F[I][K] = F[0][K] *( MATRIX^B)显然不靠谱,所以要找到F[I] = F[0] * (MATRIX^B)
然后F[I] = F[I-1] * MATRIX,然后找到F[I-1][K] 与 MATRIX的对应元素的关系,做一个预处理,就好了。
上参考别人代码后自己的代码……
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define Mod 1000000007
using namespace std;
int p,k,no_box,no_digit;
//矩阵快速幂
int cnt[10];
struct Matrix { //这样的拷贝能不能做到深拷贝?!?
long long val[105][105]; //可能会超出int
Matrix () {memset(val,0,sizeof(val));} //无参数构造函数
friend Matrix operator *(Matrix x,Matrix y) {
Matrix Ans;
for(int i = 0;i < p;i ++)
for(int j = 0;j < p;j ++)
for(int k = 0;k < p;k ++){
Ans.val[i][j] += x.val[i][k] * y.val[k][j];
Ans.val[i][j] %= Mod;
}
return Ans;
}
friend Matrix operator^(Matrix X,int Y) {
Matrix Ans;
for(int I = 0;I <= p - 1;I ++)
Ans.val[I][I] = 1;
while(Y > 0)
{
if(Y % 2 == 1) Ans = Ans * X;
X = X * X;
Y = Y >> 1;
}
return Ans;
}
}A,B;
int main()
{
int tem;
cin >> no_digit >> no_box >> k >> p;
memset(cnt,0,sizeof(cnt));
for (int i = 0; i < no_digit; i++){
cin >> tem;
cnt[tem]++;
}
for(int i = 0; i < p; i++)
for(int j = 0; j < p; j++)
for(int k = 1; k <= 9; k++)
if (cnt[k] > 0 && ((i * 10 + k) % p) == j)
B.val[i][j] += cnt[k];
A.val[0][0] = 1;//初始条件(要想清楚,或者先算出1时的情景)
A = A * (B^no_box);
cout << A.val[0][k] << '\n';
return 0;
}