赞
踩
转载请注明文本链接 http://blog.csdn.net/yangnanhai93/article/details/40441709
题目链接地址:http://ac.jobdu.com/problem.php?pid=1380
第一次这么正式的去写这个ACM的算法的博客,感觉这个题目给我的触动有点大,很多时候更多的算法需要观察,需要细心的品味题目,才能够有:“啊哈,算法”——《编程珠玑》
先说下自己的惯性思路吧,因为这个题目就是很明显一个统计的问题,所以,我一上来的就是尽量的去减少内存开销,所以我采用的是:
在我看来这个应该是没有问题的,因为int 4字节 char 1字节,因为m%n!=0,且n>=2,所以这个map的元素中的个数是小于等于5*5*10^5=2.5M的,然后我把代码精简,希望得到更小的开销,但是发现和使用int short作为map的开销是一样的,这个不能理解。
- #include <stdio.h>
- #include <map>
- using namespace std;
-
- int main()
- {
- map<int,char> mp;
- map<int,char>::iterator key;
- int n,m,num;
- while(scanf("%d%d",&n,&m)!= EOF)
- {
- mp.clear();
- while(m--)
- {
- scanf("%d",&num);
- key = mp.find(num);
- if(key == mp.end())
- mp.insert(pair<int,char>(num,'1'));
- else if(key->second<(n+'0'))
- key->second++;
- }
- key=mp.begin();
- while(key!=mp.end()&&key->second==(n+'0'))
- key++;
- printf("%d\n",key->first);
- }
- return 0;
- }
- /**************************************************************
- Problem: 1380
- User: vincent_ynh
- Language: C++
- Result: Memory Limit Exceed
- ****************************************************************/
- #include <stdio.h>
- #include <memory.h>
- int main()
- {
- int A[300000],B[2]={15,240};
- int n,m,num;
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- memset(A,0,sizeof(A));
- while(m--)
- {
- scanf("%d",&num);
- int tmp=(num-1)/2;
- int x=(num-1)%2;
- if((A[tmp]&B[x])>>(4*x)<=n)
- {
- A[tmp]=A[tmp]+(1<<(4*x));
- }
- }
- for(int i=1;;i++)
- {
- int tmp=(i-1)/2;
- int x=(i-1)%2;
- if(((A[tmp]&B[x])>>(4*x))%n!=0)
- {
- printf("%d\n",i);
- break;
- }
- }
- }
- return 0;
- }
- /**************************************************************
- Problem: 1380
- User: vincent_ynh
- Language: C++
- Result: Runtime Error
- ****************************************************************/
最后就是该题我能想到的目前最优的算法了:
我们对每一个数进行二进制编码,得到的是32 位的数,如果这个数出现了n次,那么这样的编码就应该出现了n次,如果对n取余,那么恰好就把这些出现n次的数消除了。想通了这个,然后接下来就是没有出现n次的,那么就是出现了m%n次的,当然可以是m%n+x*n,不影响的,在剩余的数组中,就剩下了lucky number的编码(每 位乘以m%n),所以,我们只需要把数组中对每一位取余(%n)同时,把非0位,改为1,位不变,最后把该数组转换成整数就可以了。
代码的主要思路我们通过例子能够发现:
2 5
1 1 2 2 3
结果是3
编码得到00000001 00000001 00000010 00000010 00000011(因为数字比较小,省略了前面3位即24个0)整合进数组之后00000033 取余之后为00000011
然后把非0的转换为1,得到00000011
把数组转换为整数为3,所以结果为3
这里补充一下“位与(&)”操作,位与(&)操作是对数字进行二进制编码,对应位如果同为1,则为1,否则为0
实际代码如下:
- #include <stdio.h>
- #include <memory.h>
-
- int main()
- {
- int A[32],m,n,num;
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- memset(A,0,sizeof(A));
- for(int j=0;j<m;j++)
- {
- scanf("%d",&num);
- for(int i=0;i<32;i++)
- {
- A[i]=A[i]+(num&1);
- A[i]=A[i]%n;
- num=num>>1;
- }
- }
- int tmp=m%n,result=0;
- for(int i=0;i<32;i++)
- {
- if(A[i]%n==tmp)
- result+=1<<i;
-
- }
- printf("%d\n",result);
- }
- return 0;
- }
- /**************************************************************
- Problem: 1380
- User: vincent_ynh
- Language: C++
- Result: Accepted
- Time:1620 ms
- Memory:1020 kb
- ****************************************************************/
欢迎任何想学习算法的人交流:vincent_ynh@163.com
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。