CF621E Wet Shark and Blocks

CF621E Wet Shark and Blocks

考虑记录哪些信息是必要的:当前是第几位,以及当前余数是多少。注意,当前填什么完全不重要,我们只在意填之前和填之后的余数。

记\(f_{k, i}\) 表示当前填了 \(k\) 位,余数为 \(i\),多少种方案。

有转移 \(f_{k, i} = \sum_{j = 0} ^ {x - 1}f_{k - 1, j} \times a_{i, j}\),其中 \(a_{i, j}\) 表示余数从 \(j\) 变成 \(i\) 的贡献。

利用滚动数组的思想可以优化掉第一维,然后就可以利用矩阵加速了。构造一个 \(x \times x\) 的矩阵 \(a\) 和一个长度为 \(x\) 的列向量 \(b\),二者都可以通过暴力枚举来初始化。

答案就是 \(a ^ {x - 1} \times b\) 的第 \(k\) 行。时间复杂度 \(O(x^3 \times \log_{2}^{b})\)。

注意矩阵快速幂的基本形式是 \(a^{x - 1} \times b\) 而不是 \(b \times a^{x - 1}\),注意矩阵乘法的运算法则。

然后就是写代码之前一定要把 \(a\) 的行、列的含义想清楚。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
int n, len, k, x;
ll num[200], cnt[200], f[200];
ll ans = 0;
const int mod = 1e9 + 7;
struct matrix{
	ll a[200][200];
	matrix(int val){
		memset(a, 0, sizeof(a));
		F(i, 1, x){
			a[i][i] = val;
		}
	}
	matrix operator *(matrix &other){
		matrix c(0);
		F(i, 1, x){
			F(j, 1, x){
				F(k, 1, x){
					c.a[i][k] = (c.a[i][k] + a[i][j] * other.a[j][k] % mod) % mod;
				}
			}
		}
		return c;
	}
};
matrix operator ^(matrix x, int y){
	matrix c(1);
	while(y){
		if(y & 1) c = c * x;
		x = x * x;
		y >>= 1;
	}
	return c;	
}
void Main(){
	cin >> n >> len >> k >> x;
	F(i, 1, n){
		int val;
		cin >> val;
		++ cnt[val];
	}
	matrix b(0);
	F(i, 0, x - 1){ // las
		F(j, 1, 9){
			b.a[(10 * i + j) % x + 1][i + 1] += cnt[j];
		}
	}
	F(i, 1, 9){
		f[i % x] += cnt[i];
	}	
	b = b ^ (len - 1);
	ll sm = 0;
	F(i, 1, x){
		sm = (sm + b.a[k + 1][i] * f[i - 1] % mod) % mod;
	}
	cout << sm << '\n';
	return ;
}
signed main(){
//	freopen("wet.in", "r", stdin);
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T = 1;
	while(T --) Main();
	return fflush(0), 0;
}
posted @ 2026-10-11 17:06  superl61  阅读(4)  评论(0)    收藏  举报