首先膜拜:
Impossible itself says 1 M possible ------ Tourist’s quote
这个题目想了两天,今晚脑子一下热,想到了第一个做法TLE,然后又找到了另外一个做法AC,回头优化第一种做法AC了。
1、对V位处理法,进行二进制分解可以求出a+b
这样再把把V*V二进制分解,可得出a*a+b*b
综合a+b,a*a+b*b如此可求出结果!
2、与官方给的方法相同
Case 1:两个数相同
我们只要把所有数字的各个数位的二进制个数保存下来,模3即可
模剩下的数组里面非零部分必定是2,把二进制还原即可
Case 2:两个数不同
两个数必定有一个位上面的二进制表示不同
开一个[i][j]31*31的数组,意思是第i位是1的所有数字第j位为1的个数
对数组里面的所有元素模3
接着,有一个很显然的想法,两个数二进制不同,那么必定有一个[i][i]是1
把i处保存的数还原,得到一个解
然后还有一个数是不能用同样的方法来找的,因为可能a&b==a
也就是说,这种方法只能找到b,找不到a
找a其实只要把[i][i]为2的二进制个数全部减去b的二进制个数,
生下来的就是a的,还原即可
我第一次做法TLE,开了一个数组[i][j]表示i位和j位同时处于一个数中的个数!这样每次处理一个数的时间为O(35*35)显然TLE!
改进优化以后便是官方的做法了!
TLE代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define m 35
int link[66][66];
int d[66];
int q[66];
int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
int n;
memset(link,0,sizeof(link));
memset(q,0,sizeof(q));
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
LL x;
scanf("%I64d",&x);
int len = 0;
while (x)
{
len++;
if (x&1)
{
d[len]=1,q[len]=(q[len]+1)%3;
}
else
d[len]=0;
x>>=1;
}
for (int i=1;i<=len;i++)
for (int j=1;j<=len;j++)
if (i!=j && d[i]&&d[j])
{
link[i][j]=(link[i][j]+1)%3;
link[j][i]=(link[j][i]+1)%3;
}
}
LL a = 0,b = 0;
for (int i=1;i<=m;i++)
{
if (q[i]==2)
{
a += (1<<(i-1));
b += (1<<(i-1));
for (int j=1;j<=m;j++)
link[i][j]=link[j][i]=0;
q[i]=0;
}
}
// printf("%I64d %I64d\n",a,b);
int k=1;
while (k<=m && q[k]==0)
k++;
while (k<=m)
{
a += (1<<(k-1));
q[k]=0;
int t = 1;
while (t<=m && link[k][t]==0)
t++;
k = t;
}
for (k = 1;k<=m;k++)
if (q[k])
b += (1<<(k-1));
LL tmp ;
if (a>b)
{
tmp = a;
a = b;
b = tmp;
}
printf("%I64d %I64d\n",a,b);
}
return 0;
}
优化后AC代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define m 37
int link[66][66];
int q[66];
int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
int n;
memset(link,0,sizeof(link));
memset(q,0,sizeof(q));
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
LL x;
scanf("%I64d",&x);
int len = 0;
int head =-1;
while (x)
{
len++;
if (x&1)
{
q[len]=(q[len]+1)%3;
if (head ==-1)
head = len;
else
link[head][len]=(link[head][len]+1)%3;
}
x>>=1;
}
}
LL a = 0,b = 0;
for (int i=1;i<=m;i++)
{
if (q[i]==2)
{
a += (1<<(i-1));
b += (1<<(i-1));
}
}
// printf("%I64d %I64d\n",a,b);
int k=1;
while (k<=m && q[k]==0)
k++;
if (k<=m)
{
for (int i=1;i<=m;i++)
if ((i==k&&q[i]==1) || (link[k][i]==1&&q[i]==1))
{
a += (1<<(i-1));
q[i]=0;
}
}
// printf("%I64d %I64d\n",a,b);
for (k = 1;k<=m;k++)
if (q[k]==1)
b += (1<<(k-1));
LL tmp ;
if (a>b)
{
tmp = a;
a = b;
b = tmp;
}
printf("%I64d %I64d\n",a,b);
}
return 0;
}
第一中做法代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define M 67
int a[M];
int b[M];
LL mysqrt(LL x)
{
LL res = (LL)sqrt((double)x);
while (res*res<x)
res++;
while (res*res>x)
res--;
return res;
}
int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
int n;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
LL x;
scanf("%I64d",&x);
LL t = x;
int k = 0;
while (t)
{
k++;
if (t&1)
a[k]=(a[k]+1)%3;
t>>=1;
}
t = x*x;
k = 0;
while (t)
{
k++;
if (t&1)
b[k]=(b[k]+1)%3;
t>>=1;
}
}
LL x= 0,y = 0;
LL c= 1;
for (int i=1;i<=63;i++)
{
x+=a[i]*c;
y+=b[i]*c;
c<<=1;
}
// printf("%I64d %I64d\n",x,y);
LL t = mysqrt(2*y-x*x);
// printf("%I64d\n",t);
printf("%I64d %I64d\n",(x-t)/2,(x+t)/2);
}
return 0;
}