「2017 山东三轮集训 Day1」Flair

模拟赛的题

好神仙啊

题面在这里


题意

有$ 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;
}

猜你喜欢

转载自www.cnblogs.com/DreamlessDreams/p/10235515.html
今日推荐