题解可以戳这个,然后建议去看一下杜教ppt。
大概就是已知若干个点值,然后可以用组合的性质用自己把自己带进去然后O(M)得到任意一个点值把。(M为多项式的次数),组合数还是很神奇的。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #define ll long long #define N 500005 #define mod 1000000007 using namespace std; int n,m,cnt,a[N],b[N],c[N],u[N],v[N],pw[N],fac[N],inv[N],p[N]; int ksm(int x,int y){ int t=1; for (; y; y>>=1,x=(ll)x*x%mod) if (y&1) t=(ll)t*x%mod; return t; } void pfs(){ int i,j; pw[1]=1; for (i=2; i<=m+1; i++){ if (!pw[i]){ pw[i]=ksm(i,m); c[++cnt]=i; } for (j=1; j<=cnt && i*c[j]<=m+1; j++){ pw[i*c[j]]=(ll)pw[i]*pw[c[j]]%mod; if (!(i%c[j])) break; } } } int cbn(int x,int y){ return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; } int main(){ scanf("%d%d",&n,&m); int i; if (m==1){ printf("%d\n",((ll)n*(n+1)>>1)%mod); return 0; } pfs(); if (n<=m){ int ans=0,base=m; for (i=1; i<=n; i++,base=(ll)base*m%mod) ans=((ll)base*pw[i]+ans)%mod; printf("%d\n",ans); return 0; } inv[0]=inv[1]=fac[0]=fac[1]=1; for (i=2; i<=m+1; i++){ inv[i]=mod-(ll)inv[mod%i]*(mod/i)%mod; fac[i]=(ll)fac[i-1]*i%mod; } a[0]=1; b[0]=0; for (i=1; i<=m+1; i++){ a[i]=(ll)a[i-1]*inv[m]%mod; b[i]=((ll)b[i-1]*inv[m]+pw[i])%mod; } for (i=1; i<=m+1; i++) inv[i]=(ll)inv[i-1]*inv[i]%mod; int t1=0,t2=0; for (i=0; i<=m+1; i++){ int tmp=cbn(m+1,i); if (i&1) tmp=mod-tmp; t1=((ll)tmp*a[i]+t1)%mod; t2=((ll)tmp*b[i]+t2)%mod; } p[0]=(ll)(mod-t2)*ksm(t1,mod-2)%mod; for (i=1; i<=m; i++) p[i]=((ll)p[0]*a[i]+b[i])%mod; u[0]=1; v[m]=1; int ans=0; for (i=1; i<=m; i++) u[i]=(ll)u[i-1]*(n-i+1)%mod; for (i=m-1; i>=0; i--) v[i]=(ll)v[i+1]*(n-i-1)%mod; for (i=0; i<=m; i++){ int tmp=(ll)u[i]*v[i]%mod*inv[i]%mod*inv[m-i]%mod; if ((m^i)&1) tmp=mod-tmp; ans=((ll)p[i]*tmp+ans)%mod; } printf("%d\n",((ll)ans*ksm(m,n)-p[0]+mod)%mod); return 0; }
by lych
2016.3.17