• 「NOI2017」泳池


    DP式子比后面的东西难推多了

    LOJ2304 

    Luogu P3824

    UOJ #316


    题意

    给定一个长度为$ n$高为$ infty$的矩形

    每个点有$ 1-P$的概率不可被选择

    求最大的和底边重合的不包含不可选点的矩形的面积为$ K$的概率

    $ n leq 10^9 k leq 10^3$


    题解

    K可以出到50000的

    首先考虑DP

    面积恰好为$ K$的概率可以差分为不高于$ K$的概率减去不高于$ K-1$的概率

    设$ f[i][j]$表示长度为$ i$的矩形,从底边起$ j$行都可选,最大面积不大于$ K$的概率

    边界为$ f[0][j]=1,f[i][j]=0 当且仅当i*j>k$

    考虑转移,要么第$ j+1$行也都可选,要么第$ j+1$行有不可选的位置

    对于第二种情况我们枚举从左到右第一个不可选的位置

    有转移方程式

    $$f[i][j]=f[i][j+1]*P^i+sum_{k=1}^iP^{k-1}(1-P)f[k-1][j+1]·f[i-k][j]$$

    我们要求的是$ f[n][0]$

    由于$ i*j leq K$因此复杂度大致是$ n·k log k$的

    可以得$ 70$分

    容易发现当$ n$远大于$ k$的时候,每连续$ k$列必然有一列最低端有不可选点

    令$ F[i]$表示当$ i>k$时,长度为$ i$的矩形的答案

    枚举从右往左第一个不可选点,有转移方程式

    $$ F[i]=f[i-k]*(1-P)*f[k-1][1]*P^{k-1}$$

    这是一个线性递推的标准形式,可以用特征多项式优化到$ O(k^2 log n)$甚至$ O(k log k log n)$

    如果采用后一种的话复杂度的瓶颈在于前面的$ O(k^2)DP$,这部分可以用分治$ NTT$优化

    然而我并没有写


    代码

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define p 998244353
    #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('
    ');}
    namespace poly{
        vector<int>R;
        int ksm(int x,int y=p-2){
            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;
        }
        void NTT(int n,vector<int>&A,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;i<n;i<<=1){
                int w=ksm(3,(p-1)/2/i);
                for(rt j=0;j<n;j+=i<<1){
                    int K=1;
                    for(rt k=0;k<i;k++,K=1ll*K*w%p){
                        int x=A[j+k],y=1ll*K*A[i+j+k]%p;
                        A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p;
                    }
                }
            }
            if(fla==-1){
                reverse(A.begin()+1,A.end());
                int invn=ksm(n);
                for(rt i=0;i<n;i++)A[i]=1ll*A[i]*invn%p;
            }
        }
        vector<int>Mul(vector<int>x,vector<int>y){
            int lim=1,sz=x.size()+y.size()-1;
            while(lim<=sz)lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            NTT(lim,x,1);NTT(lim,y,1);
            for(rt i=0;i<lim;i++)x[i]=1ll*x[i]*y[i]%p;
            NTT(lim,x,-1);x.resize(sz);
            return x;
        }
        vector<int>sqr(vector<int>x){
            int lim=1,sz=x.size()*2-1;
            while(lim<=sz)lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            NTT(lim,x,1);for(rt i=0;i<lim;i++)x[i]=1ll*x[i]*x[i]%p;
            NTT(lim,x,-1);x.resize(sz);
            return x;
        }
        vector<int>Inv(vector<int>A,int n=-1){
            if(n==-1)n=A.size();
            if(n==1)return vector<int>(1,ksm(A[0]));
            vector<int>b=Inv(A,(n+1)/2);
            int lim=1;while(lim<=n+n)lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            A.resize(n);NTT(lim,A,1);NTT(lim,b,1);
            for(rt i=0;i<lim;i++)A[i]=1ll*b[i]*(2ll-1ll*A[i]*b[i]%p)%p;
            NTT(lim,A,-1);A.resize(n);
            return A;
        }
        vector<int>Div(vector<int>A,vector<int>B){
            int n=A.size(),m=B.size();
            reverse(A.begin(),A.end());
            reverse(B.begin(),B.end());
            A.resize(n-m+1),B.resize(n-m+1);
            int lim=1;while(lim<=2*(n-m+1))lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            vector<int>ans=Mul(A,Inv(B));ans.resize(n-m+1);
            reverse(ans.begin(),ans.end());
            return ans;
        }
        vector<int>add(vector<int>A,vector<int>B){
            int len=max(A.size(),B.size());A.resize(len+1);
            for(rt i=0;i<=len;i++)(A[i]+=B[i])%=p;
            return A;
        }
        vector<int>sub(vector<int>A,vector<int>B){
            int len=max(A.size(),B.size());A.resize(len+1);
            for(rt i=0;i<=len;i++)(A[i]-=B[i])%=p;
            return A;
        }
        vector<int>Mod(vector<int>x,vector<int>y){
            if(x.size()<=y.size())return x;
              vector<int>ans=Div(x,y);
            ans=sub(x,Mul(y,ans));
            while(!ans[ans.size()-1])ans.pop_back();
            if(ans.size()>y.size())ans.resize(y.size());
            return ans;
        }
    }
    using namespace poly;
    int a[100010];
    vector<int>fmo;
    vector<int>ksm(vector<int>x,int y){
        if(y==1)return x;
        vector<int>ans=Mod(sqr(ksm(x,y>>1)),fmo);
        if(y&1){
            ans.push_back(0);
            for(rt i=ans.size()-2;i>=0;i--)ans[i+1]=ans[i],ans[i]=0;
        }
        return ans;
    }
    using namespace poly;
    int k,m,n,x,y,z,cnt,ans,K,P;
    int f[1010][1010],mi[1010];
    //f[i][j]长度为i合法高度最低至少为j的合法概率 
    void calc(int n,int K,int fla){
        memset(f,0,sizeof(f));
        for(rt i=0;i<=K+10;i++)f[0][i]=1;
        for(rt i=1;i<=K+2;i++)
        for(rt j=K/i;j>=0;j--){
            f[i][j]=1ll*f[i][j+1]*mi[i]%p;
            for(rt k=1;k<=i;k++)(f[i][j]+=1ll*f[k-1][j+1]*mi[k-1]%p*(1+p-P)%p*f[i-k][j]%p)%=p;
        }
        fmo.resize(K+2);
        for(rt j=1;j<=K+1;j++)fmo[K+1-j]=-1ll*mi[j-1]*f[j-1][1]%p*(p+1-P)%p;
        fmo[K+1]=1;int ret=0;
        if(n<=K+1)ret=f[n][0];else {
            vector<int>x;x.push_back(0);x.push_back(1);
            x=ksm(x,n);
            for(rt i=0;i<=K+1;i++)(ret+=1ll*f[i][0]*x[i]%p)%=p;
        }
        (ans+=ret*fla)%=p;
    }
    int main(){
    //    file("pool");
        n=read();K=read();x=read();y=read();P=1ll*x*ksm(y)%p;
        mi[0]=1;for(rt i=1;i<=K+2;i++)mi[i]=1ll*mi[i-1]*P%p;
        calc(n,K,1);calc(n,K-1,-1);cout<<(ans+p)%p;
        return 0;
    }
  • 相关阅读:
    学习 Message(12): 整合鼠标 Down 消息
    合并两个 Wav 文件流的函数 回复 "刘文强" 的问题
    “博客无双”第一期拍卖活动获奖名单公告
    [获奖公告]“博客无双”12月27日第一期获奖名单
    “博客无双”活动拍卖时间调整公告
    致歉
    祝大家新年快乐
    博客园电子期刊2010年12月刊发布啦
    “博客无双”拍卖活动将于14:00开始
    2011年4月微软最有价值专家(MVP)申请截止时间:2011年1月13日
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10251391.html
Copyright © 2020-2023  润新知