20 pts 暴搜
直接枚举 L 集合即可。
40 pts DP
暴力 O(n4) DP ,即设 fi,a,b,c 表示选到第 i 个,第一个序列选了 a 个,第二个序列选了 b 个,两个序列选的数中下标一样的有 c 个,直接转移即可。
64 pts 费用流
费用流。
首先,将 S 和所有 A 序列的元素连边,费用为元素的值,然后 Ai 向 Bi 连 0 边,B 序列向 T 连费用为元素的值的边即可,这些边的流量全部为 1 。
题目要求为选出来的数至少 L 个下标相同的,这意味着可以选出最多 K−L 个下标不同的数。于是 A 的每一个元素向 C 连费用为 0 流量为 1 的边,同样 D 向 B 的所有元素连费用为 0 边权为 1 的边。最后在 C 和 D 之间连接一条费用为 0 流量为 K−L 的边即可。
注意因为是要最大值,所以上面每一条边的费用全部变为其相反数即可。
100 pts 贪心模拟费用流
滑稽吧,就像 NOI2017蔬菜 一样。
首先排序把最大的 K−L 个组合送进去,也就是让这些组合流过 C→D 这条边。然后剩下 L 个组合慢慢枚举,si 表示第 i 对的使用情况,如果为 1 代表 Ai 被用了,2 代表 Bi 被用了,3 代表都被用了。如果 si 为 3 意味着第 i 对完全不需要占 C→D 的流量,提出来就好。
具体看代码。
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll ans,v1,v2,v3,maxv;
int T,n,K,L,c1,c2,res,a[N],b[N],s[N],id[N];
bool cmp_a(int x,int y) {return a[x]>a[y];}
bool cmp_b(int x,int y) {return b[x]>b[y];}
struct Node_a{int id;bool operator < (const Node_a x) const {return a[id]<a[x.id];}}tmpa;
struct Node_b{int id;bool operator < (const Node_b x) const {return b[id]<b[x.id];}}tmpb;
struct Node_c{int id;bool operator < (const Node_c x) const {return a[id]+b[id]<a[x.id]+b[x.id];}}tmpc;
priority_queue<Node_a> lora,nofa;
priority_queue<Node_b> lorb,nofb;
priority_queue<Node_c> lorc;
template <typename _Tp> inline void IN(_Tp&x) {
char ch;bool flag=0;x=0;
while(ch=getchar(),!isdigit(ch)) if(ch=='-') flag=1;
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
if(flag) x=-x;
}
void clear_heap() {
v1=v2=v3=c1=c2=res=0;
while(!lora.empty()) lora.pop();while(!lorb.empty()) lorb.pop();while(!lorc.empty()) lorc.pop();
while(!nofa.empty()) nofa.pop();while(!nofb.empty()) nofb.pop();
}
int main() {
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
IN(T);while(T--) {
IN(n),IN(K),IN(L),ans=0;
for(int i=1;i<=n;++i) IN(a[i]);
for(int i=1;i<=n;++i) IN(b[i]);
for(int i=1;i<=n;++i) s[i]=0,id[i]=i;
sort(id+1,id+1+n,cmp_a);for(int i=1;i<=K-L;++i) s[id[i]]|=1,ans+=a[id[i]];
sort(id+1,id+1+n,cmp_b);for(int i=1;i<=K-L;++i) s[id[i]]|=2,ans+=b[id[i]];
clear_heap();
for(int i=1;i<=n;++i) {
tmpa.id=tmpb.id=tmpc.id=i;
if(!s[i]) lora.push(tmpa),lorb.push(tmpb),lorc.push(tmpc);
else if(s[i]==1) lorb.push(tmpb),nofb.push(tmpb);
else if(s[i]==2) lora.push(tmpa),nofa.push(tmpa);
else ++res;
}
while(L--) {
while(!lora.empty()&&(s[lora.top().id]&1)) lora.pop();
while(!nofa.empty()&&(s[nofa.top().id]^2)) nofa.pop();
while(!lorb.empty()&&(s[lorb.top().id]&2)) lorb.pop();
while(!nofb.empty()&&(s[nofb.top().id]^1)) nofb.pop();
while(!lorc.empty()&&s[lorc.top().id]) lorc.pop();
if(res) {
int i=lora.top().id,j=lorb.top().id;
ans+=a[i]+b[j],--res,s[i]|=1,s[j]|=2;
if(s[i]^3) tmpb.id=i,nofb.push(tmpb);
if(s[j]^3) tmpa.id=j,nofa.push(tmpa);
if(i==j) ++res;
else {if(s[i]==3)++res;if(s[j]==3)++res;}
continue;
}
int i1,i2,i3,j1,j2;
if(!nofb.empty()) i1=lora.top().id,j1=nofb.top().id,v1=a[i1]+b[j1],c1=(s[i1]==2)?1:0;
if(!nofa.empty()) i2=lorb.top().id,j2=nofa.top().id,v2=b[i2]+a[j2],c2=(s[i2]==1)?1:0;
if(!lorc.empty()) i3=lorc.top().id,v3=a[i3]+b[i3];
maxv=max(v1,max(v2,v3)),ans+=maxv;
if(v1==v2&&v1==maxv) {
if(c1>c2) {s[i1]|=1,s[j1]|=2;if(s[i1]^3) nofb.push((Node_b){i1});else res++;}
else {s[i2]|=2,s[j2]|=1;if(s[i2]^3) nofa.push((Node_a){i2});else res++;}
}
else if(v1==maxv) {s[i1]|=1,s[j1]|=2;if(s[i1]^3) nofb.push((Node_b){i1});else res++;}
else if(v2==maxv) {s[i2]|=2,s[j2]|=1;if(s[i2]^3) nofa.push((Node_a){i2});else res++;}
else if(v3==maxv) lorc.pop(),s[i3]=3;
}
printf("%lld\n",ans);
}
return 0;
}
C++
2 条评论
Soulist · 2020年7月8日 10:28 下午
%%% Qiuly txdy
Qiuly · 2020年7月10日 11:46 上午
Soulist /se