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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章