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\n",ans1,ans2);
    return 0;
}

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\n",ans);
    return 0;
}
contest/1321/problem/E

原文地址:https://www.cnblogs.com/starve/p/12398306.html

时间: 2024-07-31 04:45:54

Codeforces Round #625 Div. 2 D E的相关文章

Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) A. Contest for Robots(思维题)

Polycarp is preparing the first programming contest for robots. There are nn problems in it, and a lot of robots are going to participate in it. Each robot solving the problem ii gets pipi points, and the score of each robot in the competition is cal

Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) 简单解析

A题 输入两个长度为n的数组a,b,(其中第i项是1的话代表有,0代表没有, 要求a比b数组大,对于每一项都有对应的价值pi, 尽可能控制每一项最小) 输出 要求出使得a数组比b大的pi中的最大项 思路:相同情况的就抵消掉(不许考虑),只需要考虑1.b有,a没有;2.  a有,b没有,两种情况,对于所有1情况都将对应的pi设置为1,计算总和,然后平分在情况2中 1 #include <iostream> 2 #include <bits/stdc++.h> 3 4 using na

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除

Codeforces Round #339 (Div. 2) B. Gena&#39;s Code

B. Gena's Code It's the year 4527 and the tanks game that we all know and love still exists. There also exists Great Gena's code, written in 2016. The problem this code solves is: given the number of tanks that go into the battle from each country, f

Codeforces Round #315 (Div. 1)

A. Primes or Palindromes? time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output Rikhail Mubinchik believes that the current definition of prime numbers is obsolete as they are too complex and un