出题人题解 | #Tachibana Kanade Loves Sequence#
Tachibana Kanade Loves Sequence
https://ac.nowcoder.com/acm/problem/23342
原题解链接:https://ac.nowcoder.com/discuss/173818
简单的贪心题。最后一个测试点专门卡了一下可能让部分dalao的体验极差……出题人在此谢罪qwq
题目的含义其实是可以从中选出若干个数,选择一个数代价为,你的利益为你和利益中的最小值。最大化你的利益。
我们记 ,答案为
一个显然的贪心策略,是将两个序列从大到小排序,然后考虑中较小的那一个,从它所对应的序列中选出最大的没有被选的一个数,将它选中,直到我们找不到一个大于的数。
下面我们来考虑这种贪心的正确性。假设我们在中选择了个数,中选择了个数,记这种取数方案为,其中。由于地位均等,因此我们不妨设。
假设另有一种取数方案比更优,则显然有。为什么?若存在一个下标,使得 且,则其一定选择了一个中没有的,使得,这与我们在选取中“直到我们找不到一个大于的数”矛盾。同理,可证
那么,由上可得,对应的方案,一定是从对应的方案中,将一些选择的数删去,使得答案更优。
-
若删去中的某个数 则会使减少,减少,答案会增 加 ,但根据我们的取数方案,,因此答案会变得更差,与更优矛盾
-
若删去中的某个数 则会使减少,减少。根据我们的取数方案,我们每次都是从最小的收益对应的序列中选择的数,删去后,不可能有。为什么?考虑到我们从大到小选取中的每一个数,且当且仅当时,才会选择中的数。显然,若删去后,则我们不可能选择中的数,更不可能选择。因此,必有。但考虑到我们选取时,序列中均为整数,因此显然有,这使得至少减少了,因此答案反而至少减少了,因此答案不会变得更优。
综上,我们的贪心策略时正确的。
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=(b);++i)
#define F2(i,a,b) for(int i=a;i<(b);++i)
#define dF(i,a,b) for(int i=a;i>=(b);--i)
#define MN 6000005
#define ll long long
int n,m,q,k;
int a[MN],b[MN],ap[MN],bp[MN];
int h[MN];
ll ans=0,ii=1,jj=1;
int main(){
scanf("%d",&n);
F(i,1,n)scanf("%d",a+i),ap[i]=i;
F(i,1,n)scanf("%d",b+i),bp[i]=i;
sort(ap+1,ap+n+1,[](int i,int j){return a[i]>a[j];});
sort(bp+1,bp+n+1,[](int i,int j){return b[i]>b[j];});
int i=1,j=1;
ll s1=0,s2=0;
while(i<=n||j<=n){
int s;
if(i<=n&&j<=n)s=s2<s1;
else s=j<=n;
if(s)s2+=b[bp[j++]];
else s1+=a[ap[i++]];
if(ans<min(s1,s2)-i-j+2)
ans=min(s1,s2)-i-j+2,ii=i,jj=j;
}printf("%lld\n",ans);
F2(i,1,ii)h[ap[i]]=1;
F(i,1,n)printf("%d ",h[i]);puts("");
F(i,1,n)h[i]=0;
F2(i,1,jj)h[bp[i]]=1;
F(i,1,n)printf("%d ",h[i]);
return 0;
}