• 「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)=inom{n}{a}p^a(1-p)^{n-a}$

    显然浪费的钱数$ W(a)$可以$ O(1)$计算

    然后发现$ W(a)=W(a mod 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$个物品的概率$ inom{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('
    ');}
    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;
    }
  • 相关阅读:
    Game的基本元素.[小糊涂的灵感]
    J2ME图书介绍 [小糊涂的灵感]
    j2me 这个论坛好一点.[小糊涂的灵感]
    Frame rate test for tilebased games 测试结果.[小糊涂的灵感]
    源码方式在ubuntu系统上安装ruby1.9.2
    模块全解======>>ruby的类是单继承生物、所以出现了module、实现了多继承
    在ubuntu下安装rails3.0
    在ubuntu下编写运行shell脚本
    在linux下开远程桌面访问windows的解决方法
    在命令行中打开sqlite的数据库
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10235515.html
Copyright © 2020-2023  润新知