关于进制的几道题
来源:互联网 发布:lnmp一键 安装php扩展 编辑:程序博客网 时间:2024/06/16 06:45
1.给出一堆数,其中一个数出现了1次,其他的所有的数出现了2次。求出现了一次的数。
这个就是很简单的异或操作了。
#include <cstdio>using namespace std;int main(void){ long long ans,a; int N; while(~scanf("%d", &N)){ ans = 0; for(int i = 0; i < N; ++i){ scanf("%lld",&a); ans ^= a; } printf("%lld\n",ans); } return 0;}
2.给出一堆数,其中一个数出现了1次。其他所有的数出现了3次。求出现一次的数是几。
根据上面的结论,我们很容易类比得到三进制异或,但是三进制异或是怎么样的呢?
我们可以考虑一下二进制异或的本质:对于多个数的异或,我们可以这样看:将每个数进行二进制表达分解,对于每一位,我们分别统计1出现的次数,如果出现了奇数次,则在最后的结果中,否则就是该位就不对最后的结果有贡献。
所以,这里利用二进制异或的本质:是在统计,每个数字二进制表达中,每一位1出现的总次数。
所以,由此我们可以想到,可以对于10进制的每一位,统计0-9每个数字出现的次数。出现为1次的数字才会出现在最后的结果中。
#include<stdio.h> #include<string.h> int main() { int n,i,j; while(~scanf("%d",&n)){ char s[20]; int cnt[20][10]={0}; while(n--){ scanf("%s",s); int Len=strlen(s); for(i=Len-1;i>=0;i--) cnt[Len-1-i][s[i]-'0']++; } for(i=19;i>=0;i--) for(j=0;j<=9;j++) if(cnt[i][j]%3) putchar(j+'0'); putchar('\n'); } return 0; }
需要注意的一点是:为了加快速度,这里是把数字按照字符串读入的。
我们也可以用位运算来进行上面的统计。
#include <cstdio>#include <algorithm> using namespace std; int main(void){ int N; while(~scanf("%d", &N)){ long long a; long long a1;//保存出现一次数字的异或和 long long a2;//保存出现两次的数字异或和 long long a3;//没有出现三次数字的异或和 a1 = a2 = 0; for(int i = 0; i < N; ++i){ scanf("%lld",&a); a2 |= a1&a;//更新出现两次的 a1 ^= a;//更新出现一次的,同时会抹掉第一位 //下面处理进位 a3 = ~(a1&a2);//找出没有出现的 a1 &= a3;//从第一位抹掉 a2 &= a3;//从第二位抹掉 } printf("%lld\n",a1); } return 0;}这个虽然也是O(n)的算法,但是这个常数还是很大的。
这样,我们就完美解决了这个问题。
3.给出一堆数,其中一个数字出现了Y次,其他的数字出现了X次(Y<X),求给出出现Y次数的数字。
其实,看完上面的两个问题的讨论,我们就会有想法了。
算法一:和上面一个问题的算法一一样,我们依然统计每个位上,每个数字出现的次数。最后直接暴力查找即可。
算法二:利用位运算来进行统计。
我们注意到,我们依然还是用二进制的异或来模拟X进制的异或。所以,对于进位操作,我们只有加1的情况下,才可能进位。
#include <cstdio>#include <cstring>using namespace std;long long cnt[20];int main(void){ int N; int X = 3; int Y = 1; long long a; while(~scanf("%d", &N)){ memset(cnt,0,sizeof(long long)*(X+1)); for(int i = 0; i < N; ++i){ scanf("%lld",&a); cnt[2] |= cnt[1]&a; cnt[1] ^= a; for(int j = 3; j <= X; ++j){ cnt[j] |= cnt[j-1]&cnt[1]; long long up = ~ (cnt[j-1]&cnt[1]); cnt[j-1] &= up; cnt[1] &= up; } } printf("%lld\n",cnt[Y]); } return 0;}
4.现在有一个函数random(),他会等概率的产生0-M的所有整数。现在要你利用这个函数,来设计另外一个函数rand(N),他会等概率的产生0-N的所有整数。
如果直接利用区间的伸缩变换,random()*N/M,这样会产生锯齿,0-M所有数出现的概率是不一样的。
我们可以将N表示成M进制的数,对于每一位我们进行随机。这样得到的数就是在base上是个等概率的,同时对于每个m长度内也是等概率的。
但是我们要将其变成在0-N的内等概率的,就需要考虑向n摄入。
<pre name="code" class="cpp">int rand(int n){ int base=1,ret=0; while(base<n) ret+=Random()*base,base*=m; return ret<base/n*n?ret%n:rand(n);}
- 关于进制的几道题
- 关于进制的文章
- 关于进制的题
- 关于进制的大问题
- 关于进制的计算
- 关于单链表的几道题
- 关于VIM16进制查看的问题
- 关于java的进制问题
- 关于进制的一些思考
- 关于不同进制的标志
- 关于计算机的进制转换方法
- 关于图片2进制的处理
- 关于进制之间的转换
- 关于大数的进制转换问题
- 关于进制转换的一点思考
- 关于进制之间的转化问题
- 关于进制运算的问题
- 关于C++下的进制转换
- 如何在Mac 上的IDEA 13上安装JRebel
- Cgi入门教程之:6 HTML FORM
- 奇偶校验
- hibernate.cfg.xml文件的配置模板和不同数据库的配置参数
- hdu 4734 数位dp
- 关于进制的几道题
- leetcode Multiply Strings
- 黑马程序员--javase高级基础 内省引出的javabean
- Cgi入门教程之:10 email子过程
- UVA 11624.Fire(广搜)
- 遍历Jenkins所有项目的配置
- canada goose parka-714
- LeetCode-Subsets
- Python replace()方法