Codeforces Round #625 Div. 2 D E
Posted starve
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
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
以上是关于Codeforces Round #625 Div. 2 D E的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round)
Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) 简单解析