(0413)群赛里的最后一题,有点难度。
第一眼觉得挺简单的,1000k的数,想先给它排序然后找出来。哎,这不是sb的做法嘛,那么朴素的算法,纯粹的找虐!!jh别写了,1M的空间写个毛啊。
想想,愣了。hash也是不行,没有办法,jh说肯定是啥高级数据结构来做了(嗯,我们就是很多高级数据结构不会,哎,伤心^)。其实现在想想,1M也就250K个int数,极端情况下300K是完全没有办法处理的,看来高级数据结构也不行了(如果再大点空间,估计二叉查找树和zikai学长说的set是可以实现的哈)
额,想到了3*n+2,这个数模3*n,就是剩下的那两个数模3*n了,直接这样也是没有办法来处理的。该怎么改进好呢,得再研究研究^……^
异或运算,呵呵,辉哥想到这个可以。嗯,也是,演算了一下,离散里学过的几个运算可以实现把a@a@a这种给处理掉成单位元的……这里接着想想才行。
原来位运算实现可以分解到2进制来做,模拟。哈哈,真是好东西。
a[],b[],c[][],这里a[i]表示这些数分解到第i位上的累加,模3之后就是那两个数在这个位上的值了。c[i][j]表示i位和j位是否在某个数中。
这样之后如果a[i]==2那这两个数都在这个位上有分解,各自累加上去,
如果a[i]==1就得讨论了,如果记当前分解的数在一个有分解的位置是flag,则如果c[flag][i]==1那么可以知道i位也是这个数的分解(ps,这里c[flag][i]不会为2的)
额,最近在看群论什么的,想到一一映射(双射),这些个好理论还是挺有用的哈。。。
jh是用了s和s^2分别地映射过去,这样算出来x+y=t1,x^2+y^2=t2,这个方程好解的。
总结:
以后做题要看看数据范围,时间空间。先设计好算法,先估计好复杂度才行!!
hdu上一次AC,运行了1000+Ms.不知道那个0Ms的是怎么出来结果的,求解!
群赛AC代码:(第一种方法)
#include<stdio.h>
#include<math.h>
#include<string.h>
int a[35],b[35],c[35][35];
int calculate(int s)
{
int i,j,t;
i=0;t=0;
while (s)
{
i++;
if (s%2==1)
{
a[i]++;
b[++t]=i;
}
s=s/2;
}
for (i=1;i<t ;i++ )
for (j=i+1;j<t ;j++ )
{
c[b[i]][b[j]]++;
c[b[j]][b[i]]++;
}
}
int main()
{
int t,n,i,j,s,x,y,flag,tmp;
scanf("%d",&t);
while (t--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%d",&n);
n=3*n+2;
for (i=1;i<=n ;i++ )
{
scanf("%d",&s);
calculate(s);
}
for (i=1;i<=n ;i++ )
scanf("%d",&s);
for (i=1;i<=32 ;i++ )
a[i]%=3;
for (i=32;i>=1 ;i-- )
for (j=32;j>=1 ;j-- )
c[i][j]%=3;
x=0;
flag=-1;
for (i=32;i>=1 ;i-- )
{
x*=2;
if (a[i]==2)
{
x+=1;
a[i]--;
}
else
if (a[i]==1)
{
if (flag==-1)
{
x+=1;
a[i]--;
flag=i;
}
else
{
if (c[flag][i]==1)
{
x+=1;
a[i]--;
}
}
}
}
y=0;
for (i=32;i>=1 ;i-- )
{
y=y*2;
y+=a[i];
}
if (x>y)
{
tmp=x;x=y;y=tmp;
}
printf("%d %d\n",x,y);
}
}
hdu AC代码:(第二种方法)
#include<stdio.h>
#include<string.h>
#include<math.h>
long long x,y;
int calc(int a[],long long s)
{
int i;
i=0;
while (s)
{
i++;
if (s%2==1)
{
a[i]++;
}
s=s/2;
}
return 0;
}
int main()
{
int t,i,j,n;
int a[70],b[70];
long long x,y,s;
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for (i=1; i<=n ; i++ )
{
scanf("%I64d",&s);
calc(a,s);
calc(b,s*s);
}
for (i=1; i<=65 ; i++ )
a[i]%=3;
x=0;
for (i=65; i>=1 ; i-- )
{
x*=2;
x+=a[i];
}
for (i=1; i<=65 ; i++ )
b[i]%=3;
y=0;
for (i=65; i>=1 ; i-- )
{
y*=2;
y+=b[i];
}
printf("%.0lf %.0lf\n",(double)(x-sqrt((double)2*y-x*x))/2.0,(double)(sqrt((double)2*y-x*x)+x)/2.0);
}
return 0;
}
额,C很弱,得好好看看Brian W.Kernighan和Dennis M. Ritchie的《C Programming Language》。再多了解了解编译器和编译原理才行啊