正题
题目链接点这里
考虑一个m次多项式,。
当只有一个人的时候,贡献恰好是
当有两个人的时候,贡献恰好是。
因为第m项是由转移过来的,因为我们已经规定了。
所以恰好是两个人的贡献,以此类推。
答案就等于。
发现是等比数列求和,在前面补上一个1,就等于。
小括号指的是一个多项式。
那么Q-1直接多项式求逆就可以了,因为明显-1的逆元就是-1,所以跟P是否为质数没有关系。
直接快速幂加FFT就可以了。
因为m不为0,所以减不减1其实没有意义。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1e4,maxm=maxn*4+10;
struct complex{
double x,y;
complex operator+(const complex a)const{return (complex){x+a.x,y+a.y};}
complex operator-(const complex a)const{return (complex){x-a.x,y-a.y};}
complex operator*(const complex a)const{return (complex){x*a.x-y*a.y,x*a.y+y*a.x};}
}x[maxm],y[maxm];
int n,mod,t,a,b,c;
int last[maxn+10],temp[maxn+10],tot[maxn+10],op[maxn+10];
int limit,l;
int where[maxm];
const double Pi=acos(-1.0)*2.0;
void dft(complex *now,int idft){
for(int i=0;i<limit;i++) if(i<where[i]) swap(now[i],now[where[i]]);
static complex wn,w,a,b;
for(int l=2;l<=limit;l*=2){
wn=(complex){cos(Pi/l),idft*sin(Pi/l)};
for(int i=0;i<limit;i+=l){
w=(complex){1,0};
for(int x=i,y=i+l/2;y<i+l;x++,y++,w=w*wn){
a=now[x],b=w*now[y];
now[x]=a+b;
now[y]=a-b;
}
}
}
}
void multi(int *a,int *b,int l1,int l2){
limit=1,l=0;
while(limit<l1+l2) limit*=2,l++;
for(int i=0;i<limit;i++)
where[i]=((where[i>>1]>>1)|((i&1)<<(l-1))),x[i]=y[i]=(complex){0,0};
for(int i=0;i<l1;i++) x[i]=(complex){(double)a[i],0.0};dft(x,1);
for(int i=0;i<l2;i++) y[i]=(complex){(double)b[i],0.0};dft(y,1);
for(int i=0;i<limit;i++) x[i]=x[i]*y[i];dft(x,-1);
for(int i=0;i<l1;i++) a[i]=(int)(x[i].x/limit+0.5)%mod;
}
void ksm(){
t++;
tot[0]=1;
while(t){
if(t%2) multi(tot,temp,n+1,n+1);
multi(temp,temp,n+1,n+1);
t/=2;
}
(tot[0]+=mod-1)%=mod;
}
void find_ie(int *a,int now){
if(now==1) {a[0]=mod-1;return ;}
if(now%2==0) find_ie(a,now/2);
else find_ie(a,now/2+1);
for(int i=0;i<now;i++) op[i]=2*a[i]%mod;
multi(a,a,now,now);
multi(a,temp,now,now);
for(int i=0;i<now;i++) a[i]=(op[i]+mod-a[i])%mod;
return ;
}
int main(){
scanf("%d %d %d %d %d %d",&n,&mod,&t,&a,&b,&c);
a%=mod,b%=mod,c%=mod;t=min(n,t);
temp[0]=last[0]=0;
for(int i=1;i<=n;i++) temp[i]=last[i]=(a*i%mod*i%mod+b*i%mod+c)%mod;
ksm();
for(int i=1;i<=n;i++) temp[i]=last[i];temp[0]=mod-1;
find_ie(last,n+1);//inverse element
multi(tot,last,n+1,n+1);
printf("%d",tot[n]);
}
在洛谷暂时排第四。