• Codeforces Round #625 Div. 2 D E


    D题:https://codeforces.com/contest/1321/problem/D

    题意:题目给个有向图,然后给一段序列,我们要沿着这个序列走,问走的过程中当前点到t的最短路会重构多少次,输出最小最大可能

    分析:终点是不变的,我们在按照序列走到某个位置的时候,到终点有若干条长度相同的最短路,也由此有最大最小可能;

       我们考虑最短路的dis[](各点到终点的距离)我们模拟走的过程,当前点u,下一个点v,很明显地,当dis[u]+1!=dis[v]时,肯定会重构;

       当等于是,最小可能就不要加贡献,那么最大就重u的出边造出有没有另一条满足dis[u]+1==dis[k](k!=v)若存在则最大可能加一贡献

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int M=2e5+6;
    #define pb push_back
    struct node{
        int v,cost;
        node(int vv=0,int cc=0):v(vv),cost(cc){}
        bool operator<(const node &b)const{
            return cost>b.cost;
        }
    };
    struct edge{
        int v,cost;
        edge(int vv=0,int cc=0):v(vv),cost(cc){}
    };
    vector<edge>g1[M],g2[M];
    int vis[M],dis[M],a[M];
    void dij(int n,int s){
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
            dis[i]=inf;
        priority_queue<node>que;
        while(!que.empty())
            que.pop();
        dis[s]=0;
        que.push(node(s,0));
        while(!que.empty()){
            node now=que.top();
            que.pop();
            int u=now.v;
            if(vis[u])
                continue;
            vis[u]=1;
            for(int i=0;i<g2[u].size();i++){
                int v=g2[u][i].v;
                int cost=g2[u][i].cost;
                if(!vis[v]&&dis[v]>dis[u]+cost){
                    dis[v]=dis[u]+cost;
                    que.push(node(v,dis[v]));
                }
            }
        }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            g1[u].pb(edge(v,1));
            g2[v].pb(edge(u,1));
        }
     
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d",&a[i]);
        dij(n,a[m]);
     
        int ans1=0,ans2=0;
        for(int i=2;i<=m;i++){
            int x=a[i-1],y=a[i];
            if(dis[x]!=dis[y]+1)
                ans1++,ans2++;
            else{
                int flag=0;
                for(int i=0;i<g1[x].size();i++){
                    int v=g1[x][i].v;
                    if(v!=y&&dis[x]==dis[v]+1){
                        flag=1;
                        break;
                    }
                }
                ans2+=flag;
            }
        }
        printf("%d %d
    ",ans1,ans2);
        return 0;
    }
    View Code

    E题:

    题意:给定n个剑,m个盾,每个剑和盾都有俩个属性val和cost,p个怪兽,每个怪兽都有三个属性vala(对应剑的属性),valb(对应盾的属性),cost。题目要求一定要选一剑一盾,会对答案造成cost的消耗;你可以把属性严格小于你所选的武器的怪兽消灭来得到怪兽的cost加到贡献上,要求输出最大贡献;

    分析:我们考虑枚举每一个vala作为最大值,比vala小的怪兽肯定在候选队列中,然后考虑选取哪一位置的盾来使答案最优;

       因为我们枚举的这个vala最大值,所以我们必须在[valb+1,max]中选取盾,涉及到区间,也是求区间最大值,我们考虑能否用线段树解决,于是我们把每次枚举到的valb,在线段树的[valx+1,max]加上它的cost,表示我们选了盾的属性在[valb+1,max],就可以得到他的贡献cost;

       在vala枚举的过程中我们肯定要先把vala进行升序处理,就把已经处理过的加到线段树上,区间取最大值即可;

       我们用线段树解决的盾和怪兽对盾属性的处理,那么对于剑和怪兽对剑属性,我们只要在剑属性升序的序列中找到第一个比当前vala大的位置pos,再在[pos,n]中找cost最小即可,这俩者相加就是当前vala最为最大值的最优解;

       ///实际也就分出俩部分处理,一部分(剑/盾  对 怪兽)和另一部分(剑/盾  对怪兽),任意一个用一个数据结构维护剩下的直接贪心解决;

    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18; 
    const int M=1e6+6;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    struct node{
        ll val,cost;
        bool operator<(const node &no)const{
            return val<no.val;
        }
    }a[M+6],b[M+6];
    struct Node{
        ll vala,valb,cost;
        bool operator<(const Node &No)const{
            return vala<No.vala;
        }
    }c[M+6];
    ll tr[(M<<2)+6],ly[(M<<2)+6];
    ll all[M+6],tmp[M+6],suf[M+6];
    void up(int root){
        tr[root]=max(tr[root<<1],tr[root<<1|1]);
    }
    void pushdown(int root,int l,int r){
        if(ly[root]){
            ll x=ly[root];
            tr[root<<1]+=x;
            ly[root<<1]+=x;
            tr[root<<1|1]+=x;
            ly[root<<1|1]+=x;
            ly[root]=0;
        }
    }
    void build(int root,int l,int r){
        if(l==r){
            tr[root]=-tmp[l];
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    void update(int L,int R,ll c,int root,int l,int r){
        if(L<=l&&r<=R){
            tr[root]+=c;
            ly[root]+=c;
            return ;
        }
        pushdown(root,l,r);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,c,lson);
        if(R>midd)
            update(L,R,c,rson);
        up(root); 
    }
    ll query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tr[root];
        }
        if(ly[root])
            pushdown(root,l,r);
        int midd=(l+r)>>1;
        ll res=-INF;
        if(L<=midd)
            res=query(L,R,lson);
        if(R>midd)
            res=max(res,query(L,R,rson));
        up(root);
        return res;
    }
    int main(){
        int n,m,p;
        scanf("%d%d%d",&n,&m,&p);
        ll minn1=INF,minn2=INF;
        for(int i=1;i<=n;i++)
            scanf("%lld%lld",&a[i].val,&a[i].cost),minn1=min(minn1,a[i].cost);
        for(int i=1;i<=m;i++)
            scanf("%lld%lld",&b[i].val,&b[i].cost),minn2=min(minn2,b[i].cost);
        ll ans=-minn1-minn2;///因为题目说必须要选盾和剑,所以不考虑消灭了怪兽就直接减去最小的; 
        sort(a+1,a+1+n);
        sort(b+1,b+1+m);
        for(int i=1;i<=n;i++)
            all[i]=a[i].val;
    //    all[n+1]=INF;
        ///求i~n的剑消耗的最小值 
        suf[n+1]=INF;
        for(int i=n;i>=1;i--)
            suf[i]=min(a[i].cost,suf[i+1]);
        ///初始化线段树,最优的贡献肯定是若干个价值为i的b的cost的最小的负数 
        for(int i=0;i<=M;i++)
            tmp[i]=INF;
        for(int i=1;i<=m;i++)
            tmp[b[i].val]=min(tmp[b[i].val],b[i].cost);
        build(1,1,M-1);
        for(int i=1;i<=p;i++)
            scanf("%lld%lld%lld",&c[i].vala,&c[i].valb,&c[i].cost);
        sort(c+1,c+1+p);
        for(int i=1;i<=p;i++){
        //    cout<<ans<<endl;
            update(c[i].valb+1,M-1,c[i].cost,1,1,M-1);
            ll res1=query(c[i].valb+1,M-1,1,1,M-1);///盾和怪兽对答案的贡献 
        //    cout<<res1<<endl;
            int pos=upper_bound(all+1,all+1+n,c[i].vala)-all;
            ll res2=suf[pos];///当前情况下选择的最优的剑的消耗 
            ans=max(ans,res1-res2);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    contest/1321/problem/E
    View Code
  • 相关阅读:
    <经验杂谈>C#/.Net中xml的Serialization序列化与DeSerializetion反序列化
    <经验杂谈>C#中一种最简单、最基本的反射(Reflection):通过反射获取方法函数
    应用highcharts做直观数据统计
    ASP.net获取当前页面的文件名,参数,域名等方法
    C#中唯一标识符GUID的一些知识点
    理清fineuploader无刷新上传的一些事
    webform开发经验(一):Asp.Net获取Checkbox选中的值
    C#/.Net Post获取数据流的一种简单写法
    C#中的一种按日期分文件夹的日志写法
    C# Datatable导出Excel方法
  • 原文地址:https://www.cnblogs.com/starve/p/12398306.html
Copyright © 2020-2023  润新知