CF1835C. Twin Clusters

题目大意

给出一个长为\(2^{K+1}\)的序列,每个元素在\([0,4^K)\)之间,
序列中找到两个不相交的区间使得二者的异或和相等

\(K<=17,\sum 2^{K+1}<=2^{18}\)

题解

好题,但最后没有break出去绝杀失败了,rk70=>rk150

因为元素大小是\(4^K\)级别的,和大小相关的算法(FWT)都没用了,所以不如直接随机

发现长度为\(2^{K+1}\)的序列里有\(2^K(2^{K+1}+1)\)个区间,即大于\(2*4^K\)个,那么这些区间的取值分配到\([0,4^K)\)平均每个位置有大于2个

考虑随机,发现如果按照异或值s随机,可以构造把区间集中到某些特定的s上,那样随机次数会变多(如果一个s只有<=1个区间显然选不出来),同时需要找两个区间

于是考虑直接随机一个区间[x,y],然后找另一个符合异或值s的区间:
直接把r从1=>y-1,用map找l;然后把l从n=>x+1,用map找r(\(n=2^{K+1}\)

这样找到的区间可能有交,但只要不完全包含就可以去掉交集使其合法


期望随机次数\(O(1)\),一次\(O(n\log)\),实际跑挺快

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;

int T,K,n,i,j,k,l,x,y,X1,Y1,X2,Y2;
ll a[262254],sum;
bool Find;
map<ll,int> mp;
map<ll,int> :: iterator I;

int random(int x,int y)
{
	return (32768ll*rand()+rand())%(y-x+1)+x;
}

int main()
{
	srand(time(0));
//	freopen("C.in","r",stdin);
	
	scanf("%d",&T);
	for (;T;--T)
	{
		scanf("%d",&K);n=1<<(K+1);
		fo(i,1,n) scanf("%lld",&a[i]),a[i]^=a[i-1];
		
		Find=0;
		
		fo(l,1,100)
		{
			x=random(1,n);
			y=random(1,n);
			if (x>y) swap(x,y);
			
			sum=a[y]^a[x-1];
			
			mp.clear();
			fo(i,1,n)
			{
				if (i<x)
				mp[a[i-1]]=i;
				
				I=mp.find(sum^a[i]);
				if (I!=mp.end())
				{
					X1=I->second;
					Y1=i;
					X2=x;
					Y2=y;
					
					if (X2<=Y1)
					{
						swap(X2,Y1);
						--Y1;
						++X2;
						
					}
						if (X1<=Y1 && X2<=Y2)
						{
							Find=1;
							break;
						}
				}
			}
			
			if (Find==1) break; //就是这里没break
			
			if (x==2 && y==2)
			n=n;
			
			mp.clear();
			fd(i,n,x+1)
			{
				if (y<i)
				mp[a[i]]=i;
					
				I=mp.find(sum^a[i-1]);
				if (I!=mp.end())
				{
					X1=i;
					Y1=I->second;
					X2=x;
					Y2=y;
					swap(X1,X2);
					swap(Y1,Y2);
					
					if (X2<=Y1)
					{
						swap(X2,Y1);
						--Y1;
						++X2;
						
					}
						if (X1<=Y1 && X2<=Y2)
						{
							Find=1;
							break;
						}
				}
			}
			if (Find==1) break; //就是这里没break
		}
		
		if (!Find)
		printf("%d\n",-1);
		else
		printf("%d %d %d %d\n",X1,Y1,X2,Y2);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章