[SDOI2017]序列计数
Posted fhq_treap
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2017]序列计数相关的知识,希望对你有一定的参考价值。
考虑处理如下两个条件:
- 和为\\(p\\)的倍数
- 有至少一个质数
考虑正难则反的原则,至少一个质数很难算的,我们考虑求出所有满足条件一的,还有仅由合数满足条件一的个数。
设\\(f_{i,x}\\)为取了\\(i\\)个,\\(mod\\ p = x\\)的方案数
那拼接一下\\(f_{i + j,x} = \\sum_{a + b = x(mod p)}f_{i,a}f_{j,b}\\)
考虑生成函数,那么上面这个操作等于循环卷积,那么\\(log(n)\\)次循环卷积就可以做了。
因为\\(p\\)太小,所以直接暴力卷。
[SDOI2017]序列计数
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 20000005
#define M 200
#define mod 20170408
ll n,m,p;
bool P[N];
ll f[200],g[200],F[200],G[200];
inline void sieve(){
P[1] = 0;
for(int i = 2;i <= N;++i){
if(P[i]){
for(int j = 2;j * i <= N;++j)
P[i * j] = 0;
}
}
}
ll c[M * 2];
inline void mul(ll *a,ll *b){
for(int i = 0;i < p;++i)
for(int j = 0;j < p;++j)
c[i + j] = (c[i + j] + a[i] * b[j]) % mod;
for(int i = 0;i < p;++i)
a[i] = (c[i] + c[i + p]) % mod,c[i] = c[i + p] = 0;
}
inline void powf(ll k){
F[0] = 1;
while(k){
// for(int i = 0;i < p;++i)
// std::cout<<f[i]<<" ";
if(k & 1)mul(F,f);
mul(f,f);
k >>= 1;
}
}
inline void powg(ll k){
G[0] = 1;
while(k){
if(k & 1)mul(G,g);
mul(g,g);
k >>= 1;
}
}
int main(){
std::memset(P,1,sizeof(P));
scanf("%lld%lld%lld",&n,&m,&p);
sieve();
for(int i = 1;i <= m;++i)
f[i % p] ++ ;
powf(n);
for(int i = 1;i <= m;++i)
if(!P[i])
g[i % p] ++ ;
powg(n);
std::cout<<(F[0] - G[0] + mod) % mod;
}
以上是关于[SDOI2017]序列计数的主要内容,如果未能解决你的问题,请参考以下文章