题解:P3702 [SDOI2017] 序列计数
zhangxiaoyu008 · · 题解
>题面链接<
更佳观感:
首先看到“至少有一个数是质数”就觉得不好算,一眼容斥成
那我们就考虑
状态定义:
转移:
定义
那么
我们发现这个东西好像可以矩阵快速幂!
因为
随后假设已经求出来了
那么相应的就应构造
同理将
然后写✍代码~~~
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100 + 10, M = 2e7 + 10, mod = 20170408;
int n, m, p, primes[M], cnt, cnt1[N], cnt2[N];
bool st[M];
struct Matrix{
int m, n, mat[N][N];
Matrix() {}
Matrix(int _m, int _n) {
m = _m, n = _n;
memset(mat, 0, sizeof mat);
}
inline Matrix operator * (Matrix b) {
if(n != b.m) throw "Invalid Matrix Operation.";
Matrix res(Matrix(m, b.n));
for(int i = 0; i < m; i ++)
for(int j = 0; j < b.n; j ++)
for(int k = 0; k < n; k ++)
res.mat[i][j] = (res.mat[i][j] + (LL)mat[i][k] * b.mat[k][j] % mod) % mod;
return res;
}
inline Matrix operator ^ (int k) {
if(m != n) throw "Invalid Matrix Operation.";
Matrix tmp(*this), res(Matrix(m, n));
for(int i = 0; i < m; i ++) res.mat[i][i] = 1;
while(k) {
if(k & 1) res = res * tmp;
tmp = tmp * tmp;
k >>= 1;
}
return res;
}
}A, B;
int get_ans(int *cnt) {
A = Matrix(p, p);
for(int i = 0; i < p; i ++)
for(int j = 0; j < p; j ++)
A.mat[i][j] = cnt[(i - j + p) % p];
B = Matrix(p, 1);
for(int i = 0; i < p; i ++) B.mat[i][0] = cnt[i];
return ((A ^ (n - 1)) * B).mat[0][0];
}
int main()
{
scanf("%d%d%d", &n, &m, &p);
for(int i = 1; i <= m; i ++) cnt1[i % p] ++;
st[1] = true; // 自然1不是质数
for(int i = 1; i <= m; i ++) {
if(!st[i]) primes[++ cnt] = i;
for(int j = 1; j <= cnt && primes[j] <= m / i; j ++) {
st[i * primes[j]] = true;
if(!(i % primes[j])) break;
}
}
for(int i = 1; i <= m; i ++)
if(st[i])
cnt2[i % p] ++;
printf("%d\n", (get_ans(cnt1) - get_ans(cnt2) + mod) % mod);
return 0;
}