题解 P3702 【[SDOI2017]序列计数】
sky_of_war · · 题解
我觉得这篇题解下很多矩阵解法没有写清楚矩阵怎么构造...所以我来详细地写一下
同步更新于我的博客:「LUOGU P3702」[SDOI2017]序列计数
首先这个形式显然非常不好计算,容斥一波:
我们很容易得到
向量长这样:
最后答案矩阵为
向量长这样:
最后答案矩阵为
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e2 + 10, mo = 20170408, MAXM = 2e7 + 10;
struct mat
{
int m, n, ma[MAXN][MAXN];
mat() {}
mat(int _m, int _n) :
m(_m), n(_n)
{
memset(ma, 0, sizeof(ma));
}
friend inline mat operator * (mat a, mat b)
{
mat res = mat(a.m, b.n);
for(int i = 1; i <= res.m; i++)
for(int j = 1; j <= res.n; j++)
for(int k = 1; k <= a.n; k++)
res.ma[i][j] = (res.ma[i][j] + 1ll * a.ma[i][k]
* b.ma[k][j] % mo) % mo;
return res;
}
friend inline mat operator ^ (mat a, int b)
{
mat c = a, res = mat(a.m, a.n);
for(int i = 1; i <= res.m; i++)
res.ma[i][i] = 1;
while(b)
{
if(b & 1) res = res * c;
c = c * c;
b >>= 1;
}
return res;
}
} P, Q, V, W;
int n, m, p, cnt[MAXN], compo[MAXN];
bool prime[MAXM];
int pr[MAXM];
template <class T>
inline void _read(T &x)
{
x = 0;
char t = getchar();
while(!isdigit(t) && t != '-') t = getchar();
if(t == '-')
{
_read(x);
x *= -1;
return ;
}
while(isdigit(t))
{
x = x * 10 + t - '0';
t = getchar();
}
}
int ptot = 0;
int main()
{
_read(n), _read(m), _read(p);
for(int i = 0; i < p; i++) cnt[i] = m / p;
for(int i = 1; i <= m % p; i++) cnt[i]++;
P = mat(p, p);
P.ma[1][1] = cnt[0];
for(int i = 2; i <= p; i++) P.ma[1][i] = cnt[p - i + 1];
for(int i = 2; i <= p; i++)
{
for(int j = 2; j <= p; j++)
P.ma[i][j] = P.ma[i - 1][j - 1];
P.ma[i][1] = P.ma[i - 1][p];
}
memset(prime, 1, sizeof prime);
prime[1] = false;
for(int i = 2; i <= m; i++)
{
if(prime[i] == true)
pr[++ptot] = i;
for(int j = 1; i * pr[j] <= m && j <= ptot; ++j)
{
prime[i * pr[j]] = false;
if(i % pr[j] == 0)
break;
}
}
for(int i = 1; i <= m; i++)
if(!prime[i]) compo[i % p]++;
Q = mat(p, p);
Q.ma[1][1] = compo[0];
for(int i = 2; i <= p; i++) Q.ma[1][i] = compo[p - i + 1];
for(int i = 2; i <= p; i++)
{
for(int j = 2; j <= p; j++)
Q.ma[i][j] = Q.ma[i - 1][j - 1];
Q.ma[i][1] = Q.ma[i - 1][p];
}
for(int i = 1; i <= p; i++)
for(int j = 1; j <= p; j++)
P.ma[i][j] %= mo, Q.ma[i][j] %= mo;
V = mat(p, 1);
W = mat(p, 1);
for(int i = 1; i <= p; i++) V.ma[i][1] = cnt[i - 1] % mo;
for(int i = 1; i <= p; i++) W.ma[i][1] = compo[i - 1] % mo;
P = (P ^ n - 1) * V;
Q = (Q ^ n - 1) * W;
printf("%d\n", (P.ma[1][1] - Q.ma[1][1] + mo) % mo);
return 0;
}