• [USACO 2018 Feb Gold] Tutorial


    Link:

    USACO 2018 Feb Gold 传送门

    A:

    $dp[i][j][k]$表示前$i$个中有$j$个0且末位为$k$的最优解

    状态数$O(n^3)$

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=105,INF=1<<30;
    int n,dat[MAXN],dp[MAXN][MAXN][MAXN];
    
    int main()
    {    
        scanf("%d",&n);
        for(int i=1;i<=n;i++) 
            scanf("%d",&dat[i]);
        for(int i=0;i<MAXN;i++)
            for(int j=0;j<MAXN;j++)
                for(int k=0;k<MAXN;k++)
                    dp[i][j][k]=INF;    
        
        if(dat[1]!=0) dp[1][1][0]=1;
        else dp[1][1][0]=0;
        for(int i=1;i<n;i++)
            for(int j=1;j<=i;j++)
                for(int k=0;k<=i-j;k++)
                    if(dp[i][j][k]!=INF)
                    {
                        dp[i+1][j][k+1]=min(dp[i+1][j][k+1],dp[i][j][k]+(dat[i+1]!=k+1));
                        dp[i+1][j+1][0]=min(dp[i+1][j+1][0],dp[i][j][k]+(dat[i+1]!=0));
                    }
        for(int i=1;i<=n;i++)
        {
            int res=INF;
            for(int j=0;j<=n;j++)
                res=min(res,dp[n][i][j]);
            printf("%d
    ",res);
        }
        return 0;
    }
    Problem A

    B:

    对于每一个节点分别计算其上方和下方的答案,其中下方答案明显可以一遍$dfs$

    上方答案我一开始是$O(树高)$求的,明显会被卡……

    其实可以再做一遍$dfs$,用父节点除去该棵子树的贡献再加上走到父节点的贡献即可

    注意特殊处理叶子结点

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10;
    char s[MAXN][20];
    struct edge{int nxt,to;}e[MAXN<<2];
    int n,x,head[MAXN],len[MAXN],f[MAXN],num[MAXN],tot;
    ll sum[MAXN],cnt[MAXN],tmp,res[MAXN],mn=1ll<<60,lf;
    
    void add_edge(int x,int y)
    {
        e[++tot]={head[x],y};head[x]=tot;
        e[++tot]={head[y],x};head[y]=tot;
    }
    
    void dfs1(int x,int anc)
    {
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==anc) continue;
            f[e[i].to]=x;dfs1(e[i].to,x);
            cnt[x]+=cnt[e[i].to];
            sum[x]+=sum[e[i].to]+cnt[e[i].to]*(len[e[i].to]+1);        
        }
    }
    
    void dfs2(int x,int anc)
    {
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==anc||!num[e[i].to]) continue;
            res[e[i].to]=sum[e[i].to];
            res[e[i].to]+=(res[x]-sum[e[i].to]-cnt[e[i].to]*(len[e[i].to]+1));
            res[e[i].to]+=3*(lf-cnt[e[i].to]);mn=min(mn,res[e[i].to]);
            dfs2(e[i].to,x);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s%d",s[i]+1,&num[i]);
            len[i]=strlen(s[i]+1);
            for(int j=1;j<=num[i];j++)
                scanf("%d",&x),add_edge(x,i);
            if(!num[i]) cnt[i]=1,len[i]--,lf++;
        }
        dfs1(1,0);
        res[1]=mn=sum[1];
        dfs2(1,0);
        
        printf("%lld",mn);
        return 0;
    }
    Problem B

    C:

    好像和前面一题差不多?

    可以离线从小到大加点用$set$和$multiset$维护当前点集和答案

    不过官网上的标程常数更小:反向从大到小加点,用链表维护当前最大空隙

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10;
    multiset<int,greater<int> > mx;
    set<int> s;set<int>::iterator it;
    int n,m,res[MAXN];P sw[MAXN];
    struct Query{int s,d,id;}bt[MAXN];
    bool cmp(Query a,Query b){return a.s<b.s;}
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) 
            scanf("%d",&sw[i].X),sw[i].Y=i;
        for(int i=1;i<=m;i++)
            scanf("%d%d",&bt[i].s,&bt[i].d),bt[i].id=i;
        sort(sw+1,sw+n+1);sort(bt+1,bt+m+1,cmp);
        
        int lst=1,pre,nxt;
        s.insert(1);s.insert(n);mx.insert(n-1);
        for(int i=1;i<=n;i++)
        {
            while(sw[lst].X<=bt[i].s&&lst<=n)
            {
                if(sw[lst].Y!=1&&sw[lst].Y!=n)
                {
                    it=s.lower_bound(sw[lst].Y);
                    nxt=*it;pre=*(--it);
                    mx.erase(mx.find(nxt-pre));
                    mx.insert(nxt-sw[lst].Y);mx.insert(sw[lst].Y-pre);    
                }
                s.insert(sw[lst].Y);lst++;
            }
            res[bt[i].id]=(*mx.begin()<=bt[i].d);
        }
        for(int i=1;i<=m;i++)
            printf("%d
    ",res[i]);
        return 0;
    }
    Problem C

    如果将问题转化为在原序列中大量删除的,手写链表即可

  • 相关阅读:
    Visual studio 2010 OpenGL配置
    OPENSTACK在RHEL7安装;admin创建虚拟机模板供demo使用
    hdu 1856 More is better
    AJAX基础知识点学习
    socket.io+angular.js+express.js做个聊天应用(三)
    Java中的继承
    00078_迭代器
    马尔可夫不等式与切比雪夫不等式
    特征值与特征向量
    人工智能数学参考---4、SVD矩阵分解 注意
  • 原文地址:https://www.cnblogs.com/newera/p/9602877.html
Copyright © 2020-2023  润新知