博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SDOI2015]序列统计
阅读量:4679 次
发布时间:2019-06-09

本文共 1488 字,大约阅读时间需要 4 分钟。

这题神仙的一批

看到乘法显然并不是很好做,尝试将其转化为加法

乘法变加法最常见的方式就是取\(log\)

\[\prod_{i=1}^na_i\equiv x(mod\ P)\]

就变成了

\[\sum_{i=1}^n log(a_i)\equiv log(x)(mod\ P)\]

但是在模意义下取\(log\)显然不是很可行啊

其实只需要找到一个合理的底数就好了

所以我们只需要找到原根就好了

如果\(g\)\(P\)的原根,那么\(g^0,g^1,g^2....g^{\varphi(P)-1}\)\(\varphi(P)\)个数肯定两两不同,又因为\(\varphi(P)=P-1\),所以\(g\)的幂次方恰好能表示\(mod\ P\)意义下的所有整数

于是我们就把相乘转化成了指数相加

我们设一个多项式\(f(x)\)\(f(x)\)表示\(x\)这个指数出现的次数

我们让\(f\)自己卷一下

\[f^2(x)=\sum_{i=0}^xf(i)f(x-i)\]

发现如果我们暴力\(dp\)求一下两个指数相加形成的方案也是这个柿子

于是我们就可以用卷积来代替暴力的背包\(dp\)

答案就是\(f^n(x)\)

需要一个多项式快速幂

代码

#include
#include
#include
#include
#define maxn 100005#define re register#define LL long long#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))inline int read() { char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;}const LL Mod=1004535809;const LL g[2]={3,334845270};int N,mod,T,n,len=1;int rev[maxn],tax[maxn];LL a[maxn],b[maxn],S[maxn],C[maxn];inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1ll) S=S*a%Mod;b>>=1;a=a*a%Mod;}return S;}inline void NTT(LL *f,int o) { for(re int i=0;i
>1;LL og1=quick(g[o],(Mod-1)/i); for(re int l=0;l
>=1ll; mul(b,b); }}int main(){ N=read(),mod=read(),T=read(),n=read(); for(re int i=2;i
>1]>>1)|((i&1)?len>>1:0); Quick(N); printf("%lld\n",S[tax[T]]); return 0;}

转载于:https://www.cnblogs.com/asuldb/p/10387662.html

你可能感兴趣的文章