「2017 山东三轮集训 Day1」Flair

模拟赛的题

好神仙啊

题面在这里


之前的Solution很蠢 现在已经update....


题意

有$ 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 \bmod C_1)$,即我们只关心选出物品的数量模$ C_1$意义下的每个值的概率

在模意义下建生成函数

即我们要求的多项式为$(px+1-p)^n $长度为$ C_1$的循环卷积结果

注意这里是循环卷积

暴力卷积的时间复杂度是$ O(10^8·\log n)$

一开始看到时限8s就开开心心的去写了,写完一交爆零看到10组数据,然后看到模数就扔题吃饭去了...

使用拆系数$ FFT$/三模数$ NTT$优化这个卷积即可

时间复杂度$ O(10^4·\log 10^4·\log n)$

 

然后考虑$ m>1$怎么做

其实吃饭的时候嘴巴bb出来了...吃完饭回机房比赛已经结束了...

反正本来也不可能写得出来的...

首先求$ v=\gcd(C_1,C_2..C_m)$,

根据$ NOIP2017$小凯的疑惑,最大的不能被货币表示出的面值$ kv$应该不超过最大的一对$ C$的乘积

这里好像很感性啊..求评论区给出证明QwQ

因此我们对于选出物品数量不超过$ 10^4$的特殊处理

即对于$ i \leq 10^4$求出恰好选了$ i$个物品的概率$ \binom{n}{i}·p^i·(1-p)^{1-i}$

写了个$ MTT$跑的还挺快...

不过常数依然大就是了...


$ 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[16][32768];
    void FFT(const int n,vector<cp>&A){
        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[s][k]*A[i+j+k];
                    A[j+k]=x+y,A[i+j+k]=x-y;
                }
            }
        }
    }
    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>AB(lim),CD(lim),AC(lim),BC(lim);
        for(rt i=1;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
        for(rt i=0;i<x.size();i++)AB[i].x=((ll)x[i])&32767,AB[i].y=((ll)x[i])>>15;
           for(rt i=0;i<y.size();i++)CD[i].x=((ll)y[i])&32767,CD[i].y=((ll)y[i])>>15;
           FFT(lim,AB);FFT(lim,CD);
        for(rt i=0;i<lim;i++){
            static cp na,nb,nc,nd;const int pl=(lim-1)&(lim-i);
            na=AB[i]+(cp){AB[pl].x,-AB[pl].y},nb=AB[i]-(cp){AB[pl].x,-AB[pl].y};
            nc=CD[i]+(cp){CD[pl].x,-CD[pl].y},nd=CD[i]-(cp){CD[pl].x,-CD[pl].y};
            const cp v1={0.5,0},v2={0,-0.5};
            na=na*v1;nb=nb*v2;nc=nc*v1;nd=nd*v2;
            AC[pl]=na*nc+na*nd*(cp){0,1};
            BC[pl]=nb*nc+nb*nd*(cp){0,1};        
        }
        FFT(lim,AC);FFT(lim,BC);
        vector<int>ans(v);
        for(rt i=0;i<sz;i++){
            ll v1=AC[i].x/lim+0.5,v2=AC[i].y/lim+BC[i].x/lim+0.5,v3=BC[i].y/lim+0.5;
            (ans[i%v]+=(ll)((v3%p<<30)+(v2%p<<15)+v1)%p)%=p;
        }
        return ans;
    }
}
using namespace any_module_NTT;
vector<int>a[30];
bool vis[20010];int price[20010],inv[20010];
int ksm(int x,int y){
    int ans=1;
    for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
    return ans;
}
int main(){
    for(rt i=0;(1<<i)<=16384;i++)
    for(rt j=0;j<(1<<i);j++)w[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];
        }
        cnt=10000/v;
        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);
        a[0][0]=0;a[0][1%v]=P;a[0][0]+=(100-P);
        for(rt i=1;(1<<i)<=n;i++)a[i]=Mul(a[i-1],a[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],fla=1;else ret1=Mul(ret1,a[i]);
        ll ans=0;
        for(rt i=1;i<v;i++)(ans+=1ll*ret1[i]*(v-i)%p)%=p;
        inv[0]=inv[1]=1;
        for(rt i=2;i<cnt;i++)inv[i]=1ll*inv[p%i]*(p-p/i)%p;
        for(rt i=0,C=1;i<cnt&&i<=n;i++){
            const int hf=price[i]-((i%v==0)?0:(v-i%v));
            (ans+=1ll*C%p*ksm(P,i)%p*ksm(100-P,n-i)%p*hf%p)%=p;
            C=1ll*C*(n-i)%p*inv[i+1]%p;
        }
        writeln((ans+p)%p);
    }
    return 0;
}

 

posted @ 2019-01-07 20:40  Kananix  阅读(299)  评论(0编辑  收藏  举报

Contact with me