习题:Make Them Similar(折半搜索)
题目
思路
首先如果不考虑数据范围
很容易有一个\(O(n*2^{30})\)的算法
此时我们想,如果只有值域只有\(2^{15}\) 该有多好
比较容易的可以想到折半搜索
我们用差分对数组和操作进行处理
这里的操作指的是每一位上异或1会是什么情况
最后的答案一定是全是0的数组
用map维护一下另一半就行了
总时间复杂度\(O(n*2^{15}*15)\)
这里作者脑抽了一下,将操作用vector来存,其实可以用一个数的二进制来表示的
代码
#include<iostream>
#include<vector>
#include<map>
using namespace std;
int n;
int a[205];
int s[205];
struct node
{
int a[205];
node()
{
for(int i=1;i<=n;i++)
a[i]=0;
}
friend bool operator < (const node &a,const node &b)
{
for(int i=1;i<=n;i++)
{
if(a.a[i]==b.a[i])
continue;
return a.a[i]<b.a[i];
}
return 0;
}
friend bool operator == (const node &a,const node &b)
{
for(int i=1;i<=n;i++)
if(a.a[i]!=b.a[i])
return 0;
return 1;
}
friend node operator + (const node &a,const node &b)
{
node c;
for(int i=1;i<=n;i++)
c.a[i]=a.a[i]+b.a[i];
return c;
}
}add[40];
node bas;
map<node,vector<int> >f;
int count(int val)
{
int tot=0;
while(val)
{
if(val&1)
tot++;
val>>=1;
}
return tot;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=count(a[i]);
}
n--;
for(int i=1;i<=n;i++)
s[i]=s[i+1]-s[i];
for(int i=1;i<=n;i++)
bas.a[i]=s[i];
for(int i=0;i<=29;i++)
{
for(int j=1;j<=n+1;j++)
{
if(((a[j]&(1<<i))^(1<<i))==0)
add[i].a[j]=-1;
else
add[i].a[j]=1;
}
for(int j=1;j<=n;j++)
add[i].a[j]=add[i].a[j+1]-add[i].a[j];
}
for(int i=0;i<(1<<15);i++)
{
node t;
vector<int> v;
for(int j=0;(1<<j)<=i;j++)
if(i&(1<<j))
{
t=t+add[15+j];
v.push_back(15+j);
}
f[t]=v;
}
cout<<endl;
for(int i=0;i<(1<<15);i++)
{
node t=bas;
vector<int> v;
for(int j=0;(1<<j)<=i;j++)
if(i&(1<<j))
{
t=t+add[j];
v.push_back(j);
}
for(int j=1;j<=n;j++)
t.a[j]=-t.a[j];
if(f.count(t)>0)
{
long long ans=0;
for(int i=0;i<v.size();i++)
ans=ans+(1<<v[i]);
for(int i=0;i<f[t].size();i++)
{
ans=ans+(1<<f[t][i]);
}
cout<<ans;
return 0;
}
}
cout<<"-1";
return 0;
}

浙公网安备 33010602011771号