• [USACO 2017 Dec Gold] Tutorial


    Link:

    USACO 2017 Dec Gold 传送门

    A:

    为了保证复杂度明显是从终结点往回退

    结果一开始全在想优化建边$dfs$……其实可以不用建边直接$multiset$找可行边跑$bfs$就行了

    由于保证每个点只进队列一次、被搜索到一次,因此复杂度为$O(n*log(n))$

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    typedef long long ll;
    typedef pair<int,int> P;
    typedef double db;
    const int MAXN=2e5+10;
    queue<int> q;
    multiset<P>::iterator it;
    multiset<P> sa,sb;
    int n,d,dist[MAXN],a[MAXN],b[MAXN];
    
    int main()
    {
        scanf("%d%d",&n,&d);
        for(int i=1;i<=2*n;i++) 
            scanf("%d%d",&a[i],&b[i]),a[i]=-a[i],b[i]=-b[i],dist[i]=-1;
        for(int i=1;i<=n;i++)
        {
            if(b[i]==0) q.push(i),dist[i]=1;
            else sa.insert(P(b[i],i));
            if(a[n+i]==0) q.push(n+i),dist[n+i]=1;
            else sb.insert(P(a[n+i],n+i));
        }    
        
        while(!q.empty())
        {
            int t=q.front();q.pop();
            if(t<=n)
            {
                while(true)
                {
                    it=sb.lower_bound(P(a[t],0));
                    if(it==sb.end()||(*it).X-a[t]>d) break;
                    dist[(*it).Y]=dist[t]+1;
                    q.push((*it).Y);sb.erase(it);
                }
            }
            else
            {
                while(true)
                {
                    it=sa.lower_bound(P(b[t],0));
                    if(it==sa.end()||(*it).X-b[t]>d) break;
                    dist[(*it).Y]=dist[t]+1;
                    q.push((*it).Y);sa.erase(it);
                }
            }
        }
        for(int i=1;i<=n;i++)
            printf("%d
    ",dist[i]);    
        return 0;
    }
    Problem A

    B:

    将无根树转化为有根树方便计数

    明显树形$dp$,转移$dp[i][j]=prod_{kin son} dp[k][(j+1)mod3]+dp[k][(j+2)mod3]$

    #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,MOD=1e9+7;
    struct edge{int nxt,to;}e[MAXN<<2];
    int n,k,x,y,head[MAXN],tot;ll dp[MAXN][3];
    
    void add_edge(int x,int y)
    {e[++tot].nxt=head[x];e[tot].to=y;head[x]=tot;}
    void dfs(int x,int anc)
    {
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==anc) continue;
            dfs(e[i].to,x);
            for(int j=0;j<3;j++)
                (dp[x][j]*=dp[e[i].to][(j+1)%3]+dp[e[i].to][(j+2)%3])%=MOD;
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<n;i++)
            scanf("%d%d",&x,&y),add_edge(x,y),add_edge(y,x);
        for(int i=1;i<=n;i++) 
            dp[i][0]=dp[i][1]=dp[i][2]=1;
        for(int i=1;i<=k;i++)
            scanf("%d%d",&x,&y),y--,dp[x][(y+1)%3]=dp[x][(y+2)%3]=0;
        
        dfs(1,0);
        printf("%lld",(dp[1][0]+dp[1][1]+dp[1][2])%MOD);
        return 0;
    }
    Problem B

    C:

    明显一个序列的和到达$m$后再进行扩展不会使答案更优

    于是想到用$two$ $pointers$找到所有刚刚达到$m$的区间,并用$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;ll sum,m;
    int n,f[MAXN],s[MAXN],res=1<<30;
    
    int main()
    {
        scanf("%d%lld",&n,&m);
        for(int i=1;i<=n;i++) 
            scanf("%d%d",&f[i],&s[i]);
        
        int lst=0;
        for(int i=1;i<=n;i++)
        {
            while(sum<m&&lst<=n)
                sum+=f[++lst],mx.insert(s[lst]);
            if(lst>n) break;
            res=min(res,*mx.begin());
            //multiset.erase(val)会删掉所有相同元素! 
            //因此要用multiset.erase(it)来删除 
            sum-=f[i];mx.erase(mx.find(s[i]));
        }
        printf("%d",res);
        return 0;
    }
    Problem C

    注意:

    1、可能有重复值因此要用$multiset$而非$set$

    2、$multiset.erase(val)$会删掉所有相同元素,因此要用$multiset.erase(it)$来删除

    3、使用$two$ $pointers$时注意末尾只删除不增加的情况

  • 相关阅读:
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
  • 原文地址:https://www.cnblogs.com/newera/p/9582489.html
Copyright © 2020-2023  润新知