正题
题目链接:https://www.luogu.com.cn/problem/CF618F
题目大意
给出大小为nnn,值域为[1,n][1,n][1,n]的两个可重集合A,BA,BA,B
需要你对它们各求出可重子集使得两个子集中的数字和相等
输出方案。
1≤n≤1061\leq n\le 10^61≤n≤106
解题思路
这个值域范围就很提示性的往鸽笼原理方面考虑。
此题的结论就是一定有连续子序列的解。
先搞一个前缀和A,BA,BA,B,假设An≤BnA_n\leq B_nAn≤Bn。
现在我们要求两个l,rl,rl,r满足
Ar1−Al1=Br2−Bl2A_{r_1}-A_{l_1}=B_{r_2}-B_{l_2}Ar1−Al1=Br2−Bl2
⇒Ar1−Br2=Al1−Bl2\Rightarrow A_{r_1}-B_{r_2}=A_{l_1}-B_{l_2}⇒Ar1−Br2=Al1−Bl2
现在问题就变为了求两个相同的Ax−ByA_x-B_yAx−By.
对于每个AxA_xAx(x∈[0,n]x\in[0,n]x∈[0,n]),求出一个最大的yyy使得By≤AxB_y\leq A_xBy≤Ax
那么显然有Ax−By∈[0,n−1]A_x-B_y\in[0,n-1]Ax−By∈[0,n−1],也就是Ax−ByA_x-B_yAx−By一共只有nnn种取值,而我们有n+1n+1n+1个,所以至少有两个相同的。
开两个桶记录一下出现位置就好了。
时间复杂度O(n)O(n)O(n)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e6+10;
ll n,a[N],b[N],la[N],lb[N];
signed main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-1];for(ll i=1;i<=n;i++)scanf("%lld",&b[i]),b[i]+=b[i-1];bool f=0;if(a[n]>b[n]){for(ll i=1;i<=n;i++)swap(a[i],b[i]);f=1;}ll ala,alb,ara,arb;for(ll i=0,j=0;i<=n;i++){while(b[j]<=a[i])j++;j--;if(la[a[i]-b[j]]){ala=la[a[i]-b[j]];alb=lb[a[i]-b[j]];ara=i;arb=j;}la[a[i]-b[j]]=i+1;lb[a[i]-b[j]]=j+1;}if(f)swap(ala,alb),swap(ara,arb);printf("%lld\n",ara-ala+1);for(ll i=ala;i<=ara;i++)printf("%lld ",i);printf("\n%lld\n",arb-alb+1);for(ll i=alb;i<=arb;i++)printf("%lld ",i);return 0;
}