CF1257F Make Them Similar

題目鏈接

題意分析

一看這道題我們 我們第一反應是枚舉然後判斷 但是這樣的複雜度達到了\(O(2^{30}*n)\)

很顯然是過不了的

我們冷靜一波可以發現 如果將每一個數的前15位以及後15位拆開的話 也就是隻考慮15位 這個複雜度是可以接受的

那麼我們可以考慮使用Meet in The Middle

關鍵是匹配該如何匹配

我們對於前十五位 處理出一個序列\(popcount(a1 \bigoplus x)-popcount(ai \bigoplus x)\)

我們對於後十五位 處理出一個序列\(popcount(a1 \bigoplus x)-popcount(ai \bigoplus x)\)

我們把題意轉化一下就可以發現 對於我們要求的x 上下兩個序列是依次互爲相反數的

那麼我們將下面的序列取反 就是\(popcount(ai \bigoplus x)-popcount(a1 \bigoplus x)\) 也就成爲了相等關係

這就成爲了匹配標準

具體實現的時候 可以使用vector存儲系列 然後使用map對於vector進行標記

強大的STL啊!

CODE:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#define N 33000
using namespace std;
int n;bool flag;
int num[N];
vector<int> G;
map<vector<int>,int> vis;
int popcount(int x)
{
	int res=0;
	while(x)
	{
		x-=x&-x;
		++res;
	}
//	printf("pop(%d) = %d\n",tmp,res);
	return res;
}
int main()
{
	scanf("%d",&n);vis.clear();
	for(int i=1;i<=n;++i) scanf("%d",&num[i]);
	for(int i=0;i<(1<<15);++i)
	{
		G.clear();
		int tmp=popcount(i^(num[1]&((1<<15)-1)));
		for(int j=2;j<=n;++j)
		{
			int x=i^(num[j]&((1<<15)-1));
			G.push_back(popcount(x)-tmp);
		}
		vis[G]=i;
	}
	for(int i=0;i<(1<<15);++i)
	{
		G.clear();
		int tmp=popcount(i^(num[1]>>15));
		for(int j=2;j<=n;++j)
		{
			int x=i^(num[j]>>15);
			G.push_back(tmp-popcount(x));
		}
		if(vis.count(G))
		{
			printf("%d\n",(i<<15)+vis[G]);
			flag=1;
			break;
		}
	}
	if(flag==0) puts("-1"); 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章