Codeforces Contest 730I Olympiad in Programming and Sports —— 两个值只能选一个的情况下选一些的最大值

    xiaoxiao2023-11-09  150

    This way

    题意:

    给你n个人参与两种比赛的得分,同一个人两个比赛只能参与一个比赛。问你如果让a个人去参加第一场比赛,b个人去参加第二场比赛,问你最多得分为多少。

    题解:

    dp,贪心,网络流都可以做啊,最简单的是网络流,5分钟就好了。 但是我写的是贪心,首先我们先按照第一个比赛排序,然后取前面a个,之后我们考虑b,那么我们假设要替让其中的某些a变成b,那么肯定是要使得要替换的a最大,那么我们从大到小枚举没有访问过的a,在枚举b,如果这个位置是假设a,那么我们考虑将其替换之后得到的值:sa[pos].a+sa[i].b-sa[i].a;,如果这个位置没有被访问过,那么如果将它加入b,得到的就是sa[i].b。如果这个位置已经是b了,continue。

    #include<bits/stdc++.h> using namespace std; const int N=3e3+5; vector<int>ansa,ansb; struct node { int a,b,id; }sa[N]; int vis[N]; bool cmp1(node a,node b) { return a.a>b.a; } int main() { int n,a,b,sum=0; scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;i++) scanf("%d",&sa[i].a),sa[i].id=i; for(int i=1;i<=n;i++) scanf("%d",&sa[i].b); sort(sa+1,sa+1+n,cmp1); for(int i=1;i<=a;i++) vis[i]=1; while(b--) { int pos=a+1; while(vis[pos]) pos++; int mx=0,val,p; for(int i=1;i<=n;i++) { val=0; if(!vis[i]) val=sa[i].b; else if(vis[i]==1) val=sa[pos].a+sa[i].b-sa[i].a; if(val>mx) mx=val,p=i; } if(vis[p]) vis[pos]=1; vis[p]=2; } for(int i=1;i<=n;i++) { if(vis[i]==1) sum+=sa[i].a,ansa.push_back(sa[i].id); else if(vis[i]==2) sum+=sa[i].b,ansb.push_back(sa[i].id); } printf("%d\n",sum); for(int i=0;i<ansa.size();i++) printf("%d%c",ansa[i],i==ansa.size()-1?'\n':' '); for(int i=0;i<ansb.size();i++) printf("%d%c",ansb[i],i==ansb.size()-1?'\n':' '); return 0; }
    最新回复(0)