模拟赛的题
好神仙啊
题意
有$ n$个商品价格均为$ 1$,您有$ m$种面值的货币,面值为$ C_1..C_m$
每种物品你有$ P$的概率选取,然后你需要选出若干货币购买这些物品
购买商品不存在找零,求浪费在找零上的钱的期望对$ 1e9+7$取模
$ n \leq 10^9 \ m \leq 10^2 \ C_iC_j \leq 10^4$
$Solution $
垃圾模数毁我青春
首先考虑$ m=1$怎么做
枚举花的钱$ a$
概率为$ P(a)=\binom{n}{a}p^a(1-p)^{n-a}$
显然浪费的钱数$ W(a)$可以$ O(1)$计算了
然后发现$ W(a)=W(a \ mod \ C_1)$
因此设$ F(i,j)$表示前$ 2^i$个物品,选出物品数量$ mod \ C_1 = j$的概率
把$F(i)$当作一个多项式则有$ F(i)=F(i-1)^2$
暴力卷积的时间复杂度是$ O(10^8·log_2(n))$
一开始看到时限8s就开开心心的去写了,写完一交爆零看到10组数据,然后看到模数就扔题吃饭去了...
使用拆系数$ FFT$/三模数$ NTT$优化这个卷积即可
时间复杂度$ O(10^4·log_2(10^4)·log_2(n))$
然后考虑$ m>1$怎么做
其实吃饭的时候嘴巴bb出来了...吃完饭回机房比赛已经结束了...
反正本来也不可能写得出来的...
首先求$ v=gcd(C_1,C_2..C_m)$,
根据$ NOIP2017$小凯的疑惑,最大的不能被货币表示出的面值$ kv$应该不超过最大的一对$ C$的乘积
这里好像很感性啊..求评论区给出证明QwQ
因此我们对于选出物品数量不超过$ 10^4$的特殊处理
形象化地,我们先按照$ m=1$做循环卷积,然后再以$ x^{10000}$为模数做非循环卷积
非循环卷积的系数就是表示出该面值的概率
对于这部分特殊处理,对于选出物品数量超过$ 10000$的情况,我们认为所有$ v$的倍数都能被表示
这样就完成了
然后我的代码莫名大常数,本机接近$ 8s$(没写MTT)(待update)
然后只能各种玄学卡常....
$ my \ code$
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #define block 32768 #define p 1000000007 #define rt register int #define ll long long using namespace std; inline ll read(){ ll x=0;char zf=1;char ch=getchar(); while(ch!='-'&&!isdigit(ch))ch=getchar(); if(ch=='-')zf=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int k,m,n,x,y,z,cnt,ans,v; namespace any_module_NTT{ vector<int>R; const double PI=acos(-1.0); struct cp{ double x,y; cp operator +(const cp s)const{return {x+s.x,y+s.y};} cp operator -(const cp s)const{return {x-s.x,y-s.y};} cp operator *(const cp s)const{return {x*s.x-y*s.y,x*s.y+y*s.x};} }w[2][16][32768]; void FFT(const int n,vector<cp>&A,const int fla){ A.resize(n); for(rt i=0;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]); for(rt i=1,s=0;i<n;i<<=1,s++){ for(rt j=0;j<n;j+=i<<1){ for(rt k=0;k<i;k++){ const register cp x=A[j+k],y=w[fla+1>>1][s][k]*A[i+j+k]; A[j+k]=x+y,A[i+j+k]=x-y; } } } if(fla==-1)for(rt i=0;i<n;i++)A[i].x/=n,A[i].y=0; } vector<int>Mul(vector<int>x,vector<int>y){ int sz=x.size()+y.size()-1,lim=1; while(lim<=sz)lim<<=1;R.resize(lim); vector<cp>A(lim),B(lim),C(lim),D(lim); for(rt i=1;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1); x.resize(lim);y.resize(lim); for(rt i=0;i<lim;i++)A[i].x=((ll)x[i])/32768,A[i].y=0; for(rt i=0;i<lim;i++)B[i].x=((ll)x[i])%32768,B[i].y=0; for(rt i=0;i<lim;i++)C[i].x=((ll)y[i])/32768,C[i].y=0; for(rt i=0;i<lim;i++)D[i].x=((ll)y[i])%32768,D[i].y=0; FFT(lim,A,1);FFT(lim,B,1);FFT(lim,C,1);FFT(lim,D,1); vector<cp>AC(lim),AD(lim),BC(lim),BD(lim); for(rt i=0;i<lim;i++)AC[i]=A[i]*C[i],AD[i]=A[i]*D[i],BC[i]=B[i]*C[i],BD[i]=B[i]*D[i]; FFT(lim,AC,-1);FFT(lim,AD,-1);FFT(lim,BC,-1);FFT(lim,BD,-1); vector<int>ans(sz); for(rt i=0;i<sz;i++)ans[i]=(ll)((ll)(AC[i].x+0.5)%p*block%p*block%p+ (ll)(AD[i].x+BC[i].x+0.5)%p*block%p+(ll)(BD[i].x+0.5)%p+0.5)%p; return ans; } vector<int>Mul(vector<int>x){//自乘 int sz=x.size()*2-1,lim=1; while(lim<=sz)lim<<=1;R.resize(lim); vector<cp>A(lim),B(lim); for(rt i=1;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1); x.resize(lim); for(rt i=0;i<lim;i++)A[i].x=((ll)x[i])/32768,A[i].y=0; for(rt i=0;i<lim;i++)B[i].x=((ll)x[i])%32768,B[i].y=0; //C=A D=B FFT(lim,A,1);FFT(lim,B,1); vector<cp>AC(lim),BC(lim),BD(lim); for(rt i=0;i<lim;i++)AC[i]=A[i]*A[i],BC[i]=B[i]*A[i],BD[i]=B[i]*B[i]; FFT(lim,AC,-1);FFT(lim,BC,-1);FFT(lim,BD,-1); vector<int>ans(sz); for(rt i=0;i<sz;i++)ans[i]=(ll)((ll)(AC[i].x+0.5)%p*block%p*block%p+ (ll)(BC[i].x*2+0.5)%p*block%p+(ll)(BD[i].x+0.5)%p+0.5)%p; return ans; } } using namespace any_module_NTT; vector<int>a[30],b[30]; vector<int>Mul1(vector<int>x,vector<int>y){ vector<int>ret; x.resize(v);y.resize(v); ret=Mul(x,y); for(rt i=v;i<ret.size();i++)(ret[i%v]+=ret[i])%=p,ret[i]=0; ret.resize(v); return ret; } vector<int>Mul2(vector<int>x,vector<int>y){ vector<int>ret; x.resize(10001);y.resize(10001); ret=Mul(x,y); ret.resize(10001); return ret; } vector<int>Mul1(vector<int>x){ vector<int>ret; x.resize(v);ret=Mul(x); for(rt i=v;i<ret.size();i++)(ret[i%v]+=ret[i])%=p,ret[i]=0; ret.resize(v); return ret; } vector<int>Mul2(vector<int>x){ vector<int>ret;x.resize(10001); ret=Mul(x);ret.resize(10001); return ret; } bool vis[20010];int price[20010]; int main(){ //file("flair"); for(rt i=0;(1<<i)<=32768;i++) for(rt j=0;j<(1<<i);j++)w[0][i][j]={cos(PI*j/(1<<i)),sin(PI*j/(1<<i))}, w[1][i][j]={cos(PI*j/(1<<i)),-sin(PI*j/(1<<i))}; for(rt T=read();T;T--){ n=read();m=read();int P=read();v=0; memset(vis,0,sizeof(vis));vis[0]=1; for(rt i=1;i<=m;i++){ x=read(); v=__gcd(v,x); for(rt j=x;j<=20000;j++)vis[j]|=vis[j-x]; } for(rt i=20000;i>=0;i--)if(vis[i])price[i]=0;else price[i]=price[i+1]+1; for(rt i=0;i<30;i++)a[i].resize(v),b[i].resize(10010); a[0][0]=0;a[0][1%v]=P;a[0][0]+=(100-P);b[0][1]=P;b[0][0]=100-P; for(rt i=1;(1<<i)<=n;i++)a[i]=Mul1(a[i-1]); for(rt i=1;(1<<i)<=n;i++)b[i]=Mul2(b[i-1]); vector<int>ret1(v),ret2(v);bool fla=0; for(rt i=0;(1<<i)<=n;i++)if(n>>i&1)if(!fla){ ret1=a[i],ret2=b[i],fla=1; }else ret1=Mul1(ret1,a[i]),ret2=Mul2(ret2,b[i]); ll ans=0; for(rt i=1;i<v;i++)(ans+=1ll*ret1[i]*(v-i)%p)%=p; for(rt i=0;i<=10000;i++){ const int hf=(i%v==0)?0:(v-i%v); (ans+=1ll*ret2[i]*(price[i]-hf)%p)%=p; } writeln((ans+p)%p); } return 0; }