zoukankan      html  css  js  c++  java
  • 2019牛客多校第10场

    A:01概率退背包,这是赛后看题解补的,概率的背包和普通的背包有点不太一样,但思想还是差不多的

    /*
    n张牌带权值ai随机洗牌,然后抽牌
    将每次抽到的ai累计到sum,可以重复抽牌,也可以停止
    如果最后sum在区间(a,b]则胜利,反之失败
    问获胜概率
    
    先考虑该问题的弱化版:从n张牌里选出点数总和在(a,b]区间的概率
    用一个二维的背包可以解决dp[k,i,j]表示前k张牌选i张点数和为j的概率
    dp[k][i][j]=dp[k-1][i][j](第k张牌不选的情况)+dp[k-1][i-1][j-x[k]]*i/(n-i+1)
    (选择第k张牌的情况:从之前选的i张里选一张,总共有i种策略,其位置用k代替,在剩下n-i+1张牌里选k的概率是1/(n-i+1)) 
    
    再来考虑这道题的情况,和弱化版不同之处在于:当前k-1张牌的和>a时,第k张牌是不同用取的
    所以我们先假设第k张牌不选,前k-1张牌的点数总和范围就是(a-x,min(a,b-x)) 
    那么前k-1张牌怎么取是无所谓的,所以我们枚举最后一张牌选idx,除了这张牌之外的牌求一次背包dp,dp[i][j]表示除了idx,选i张牌凑出j的概率 
    
    转化为每种情况的概率对答案的贡献
    用f[k][i][j]表示在n张牌中选i张,凑出分数j的概率,显然是个背包问题
    f[k][i][j]=f[k-1][i][j]+f[k-1][i-1][j-x[k]]*i/(n-i+1);
    意义为在前k-1个中取i张牌凑出分数j的概率+在k-1个中取i-1张牌凑出分数j-x[k]的概率
    最后*i/(n-i+1)是因为在剩下n-i+1张牌中抽到k的概率是1/(n-i+1),在i张牌里抽i-1的情况有i种
    
    枚举最后一张抽的牌idx,抽完这张牌获胜的要求是之前的点数为(a-x,min(a,b-x)),
    dp[i][j]表示除了牌idx,在剩余的牌中抽的i张凑出j分的概率
    显然有dp[i][j]=f[n-1][i][j],每个dp[i][j]对答案的贡献是dp[i][j]/(n-i)
    意义是先取了i张牌凑出点数j,然后最后一张取idx的概率是1/(n-i),所以每种状态的贡献要*1/(n-i)
        
    计算复杂度:外层枚举每一张不选的牌,内层O(n^3)求f,O(n^2)求dp[i][j]的贡献,O(n^4)TLE
    考虑到在n张牌中不选一张牌,可用01退背包,即先预处理选没有不选的情况下的f,然后枚举删掉一张牌的影响即可
    这样计算f的复杂度降到O(n^2),
    设当前不取牌k,dp[i][j]=f[n][i][j]-dp[i-1][j-x[k]]*i/(n-i+1)
    意义是无限制的概率-留着位置让k被选中的总概率,即在i张牌中任意挑一张不选,凑成体积j-x[k]的总概率*第i张牌选到k的概率(1/n-i+1) 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 505
    typedef double db;
    db f[2][maxn][maxn],dp[maxn][maxn];
    int n,a,b,x[maxn];
    
    int main(){
        cin>>n>>a>>b;
        for(int i=1;i<=n;i++)scanf("%d",&x[i]);
        f[0][0][0]=1;int cur=0;
        for(int k=1;k<=n;k++){
            cur^=1;
            for(int i=0;i<=k;i++)
                for(int j=0;j<=b;j++){
                    f[cur][i][j]=f[cur^1][i][j];//不选第k张 
                    if(i>0 && j>=x[k])//选第k张 
                        f[cur][i][j]+=f[cur^1][i-1][j-x[k]]*i/(n-i+1); 
                }
        }
        //f[cur][i][j]就是前n张选i张凑j的概率
        //枚举每张不选的idx,进行退背包,求总概率
        db ans=0; 
        for(int idx=1;idx<=n;idx++){
            memset(dp,0,sizeof dp);
            for(int i=0;i<n;i++)//除idx外选i张
                for(int j=0;j<=b;j++){//凑出体积b 
                    dp[i][j]=f[cur][i][j]; 
                    if(i>0 && j>=x[idx])
                        dp[i][j]-=dp[i-1][j-x[idx]]*i/(n-i+1);
                }
            int L=max(0,a-x[idx]+1),R=min(a,b-x[idx]);//求点数在这个范围的概率和 
            for(int i=0;i<n;i++)
                for(int j=L;j<=R;j++)
                    ans+=dp[i][j]/(n-i);//剩下的n-i张牌翻到idx的概率为1/(n-i) 
        }
        printf("%.10lf
    ",ans);
        return 0;
    }
    View Code

    B:斐波那契数列

    D:大数ex_crt

    E:希尔伯特排序,分形法

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1000005
    #define ll long long
    struct Node{ll x,y,id;}p[maxn];
    ll n,k;
     
    long long f(int n, int x, int y) {
        if (n == 0) return 1;
        int m = 1 << (n - 1);
        if (x <= m && y <= m)return f(n - 1, y, x);
        if (x > m && y <= m) return 3LL * m * m + f(n - 1, m-y+ 1, m * 2 - x + 1);
        if (x <= m && y > m)return 1LL * m * m + f(n - 1, x, y - m);
        if (x > m && y > m)return 2LL * m * m + f(n - 1, x - m, y - m);
    }
    int cmp(Node &a,Node &b){return a.id<b.id;}
    int main(){
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&p[i].x,&p[i].y);
            swap(p[i].x,p[i].y);
            p[i].id=f(k,p[i].x,p[i].y);
        }
        sort(p+1,p+1+n,cmp);
        for(int i=1;i<=n;i++){
            swap(p[i].x,p[i].y);
            cout<<p[i].x<<" "<<p[i].y<<endl;
        }
    }
    View Code

    F:数据结构(加速dp?)

    #include<bits/stdc++.h>
     
    using namespace std;
     
    #define maxn 500005
     
    int r,n,x[maxn],y[maxn];
     
    int cnt[maxn],a[maxn];//?y[i]???????
     
    vector<int> v[maxn];//??x???y??
     
    template<typename T>
     
    inline void rd(T&x){
     
        x=0;int f=1;char ch=getchar();
     
        while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
     
        while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
     
        x*=f;
     
    }
     
       
     
    #define lson l,m,rt<<1
     
    #define rson m+1,r,rt<<1|1
     
    int seg[maxn<<2];
     
    void pushup(int rt){
     
        seg[rt]=max(seg[rt<<1],seg[rt<<1|1]);
     
    }
     
    void build(int l, int r, int rt) {
     
      if (l == r) {
     
        seg[rt] = a[l];
     
        return;
     
      }
     
      int m = l + r >> 1;
     
      build(lson);
     
      build(rson);
     
      pushup(rt);
     
    }
     
    void update(int p, int x,int l,int r,int rt) {
     
      if (l == r) {
     
        seg[rt] += x;
     
        return;
     
      }
     
      int m = l + r >> 1;
     
      if (p <= m)
     
        update(p,x,lson);
     
      else
     
        update(p,x,rson);
     
      pushup(rt);
     
    }
     
      
     
    int main(){
     
        //freopen("2.txt","r",stdin);
     
        rd(n);rd(r);
     
        int xMax=0,yMax=0;
     
        for(int i=1;i<=n;i++){
     
            rd(x[i]);rd(y[i]);
     
            x[i]++,y[i]++;
     
            xMax=max(xMax,x[i]);
     
            yMax=max(yMax,y[i]);
     
            v[x[i]].push_back(y[i]);
     
            cnt[y[i]]++;
     
        }
     
        for(int i=1;i<=yMax;i++){
     
            a[i]=cnt[i];
     
            if(i+r<=xMax)a[i]+=cnt[i+r];
     
            if(i+2*r<=xMax)a[i]+=cnt[i+2*r];
     
        }
     
        build(1,yMax,1);//?????a[i]
     
           
     
               
     
        int ans=0;
     
        for(int xx=1;xx<=xMax;xx++){
     
             
     
            int sum=v[xx].size()/*+v[xx+r].size()+v[xx+2*r].size()*/;//x????
     
            for(int j=0;j<v[xx].size();++j){//???1?x????
     
                int yy=v[xx][j];
     
                update(yy,-1,1,yMax,1);
     
                if(yy>r)
     
                    update(yy-r,-1,1,yMax,1);
     
                if(yy>2*r)
     
                    update(yy-2*r,-1,1,yMax,1);    
     
            }
     
            if(xx+r<=xMax){
     
                sum+=v[xx+r].size();
     
                for(int j=0;j<v[xx+r].size();++j){//???2?x????
     
                    int yy=v[xx+r][j];
     
                    update(yy,-1,1,yMax,1);
     
                    if(yy>r)
     
                        update(yy-r,-1,1,yMax,1);
     
                    if(yy>2*r)
     
                        update(yy-2*r,-1,1,yMax,1);    
     
                }
     
            }
     
            if(xx+2*r<=xMax){
     
                sum+=v[xx+r*2].size();
     
                for(int j=0;j<v[xx+2*r].size();++j){//???3?x????
     
                    int yy=v[xx+2*r][j];
     
                    update(yy,-1,1,yMax,1);
     
                    if(yy>r)
     
                        update(yy-r,-1,1,yMax,1);
     
                    if(yy>2*r)
     
                        update(yy-2*r,-1,1,yMax,1);    
     
                }
     
            }
     
            sum+=seg[1];
     
            for(int j=0;j<v[xx].size();++j){//???1?x????
     
                int yy=v[xx][j];
     
                update(yy,1,1,yMax,1);
     
                if(yy>r)
     
                    update(yy-r,1,1,yMax,1);
     
                if(yy>2*r)
     
                    update(yy-2*r,1,1,yMax,1);     
     
            }
     
            if(xx+r<=xMax){
     
                for(int j=0;j<v[xx+r].size();++j){//???2?x????
     
                    int yy=v[xx+r][j];
     
                    update(yy,1,1,yMax,1);
     
                    if(yy>r)
     
                        update(yy-r,1,1,yMax,1);
     
                    if(yy>2*r)
     
                        update(yy-2*r,1,1,yMax,1);     
     
                }
     
            }
     
            if(xx+2*r<=xMax){
     
                for(int j=0;j<v[xx+2*r].size();++j){//???3?x????
     
                    int yy=v[xx+2*r][j];
     
                    update(yy,1,1,yMax,1);
     
                    if(yy>r)
     
                        update(yy-r,1,1,yMax,1);
     
                    if(yy>2*r)
     
                        update(yy-2*r,1,1,yMax,1);     
     
                }
     
            }
     
            ans=max(ans,sum);
     
        }
     
        cout<<ans<<endl;
     
    }
    View Code

    H:同构图

    J:斜率优化(分治)加速dp,待补

  • 相关阅读:
    【贪心+DFS】D. Field expansion
    【贪心+博弈】C. Naming Company
    【dp】E. Selling Souvenirs
    【multimap的应用】D. Array Division
    内存变量边界对齐
    3.8 高级检索方式(二)
    3.7 高级检索方式(一)
    openGL加载obj文件+绘制大脑表层+高亮染色
    3.6 Lucene基本检索+关键词高亮+分页
    3.5 实例讲解Lucene索引的结构设计
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11372255.html
Copyright © 2011-2022 走看看