HDU3972-求多余的两个数
来源:互联网 发布:erp生产管理系统源码 编辑:程序博客网 时间:2024/05/22 02:53
首先膜拜:
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 35int 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 37int 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 67int 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;}
- HDU3972-求多余的两个数
- 求两个数中大的数
- 求两个数的最大公约数
- 求两个数的最大公约数
- 求两个数的最小公倍数
- 求两个数的最大公约数
- 求两个数的最小公倍数
- 求两个数的最大公约数
- 求两个数的最大公约数
- 求两个数的最大公约数
- 求两个数的最大公约数
- 求两个数的最大值
- 求两个数的最大公约数
- 求两个数的最大公约数
- 求两个数的和
- 求两个数的最大公约数
- 求两个数的最大值
- 求两个数的最大公约数
- win7 64位下android开发环境的搭建
- DAPM系列文章
- 卸载oracle 11g r2 for windows (x64)时应指定数据库ASMIFS 使用的存储类型为“FS”
- IBOutletCollection
- 曲婉婷-----没有什么不同
- HDU3972-求多余的两个数
- hdfs工作原理
- iOS中后台运行
- 博客变迁
- POJ 1426 ——Find The Multiple
- InitCommonControls
- 解读QML之四
- STM32 PWM功能
- 注解