转载请注明文本链接 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
****************************************************************/

第二个略微能够降低空间的思路是,发现仅仅须要4位存储就能够了,然后用位去存储,这里,由于我个人的理解题目失误,误觉得是1-10^6个数,然后写了一个用位存储的代码,非常少写位操作的代码,写得比較难看,可是觉得作为一个精益求精的coder还是须要很多其它的使用的,《编程珠玑》中的第一个电话本的样例给我的触动特别大,让我感受到代码原来能够如此的巧妙,好吧,扯远了,这里贴一下,假设数据的范围小的时候,也能够使用例如以下位存储代码:

#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

最新文章

  1. 排序合并连接(sort merge join)的原理
  2. sevice__属性介绍: android:exported
  3. 分享5种风格的 jQuery 分页效果【附代码】
  4. css中的定位和框模型问题
  5. 压缩html 减小存储空间
  6. typeid关键字
  7. mysql 参数:[read_buffer_size] [sort_buffer_size] [read_rnd_buffer_size] [tmp_table_size]---图解
  8. PKI(公钥基础设施)基础知识笔记
  9. 数据结构--二叉查找树的java实现
  10. MATLAB命令大全+注释小结
  11. Python 爬虫-进阶开发之路
  12. 多线程(5)async&amp;await
  13. Rails6新增rails db:system:change更换数据库
  14. vs开发/IIS 遇到的问题--------笔记
  15. 两个inline-block消除间距和对齐(vertical-align)
  16. VirtualBox安装增强工具时:Unable to install guest additions: unknown filesystem type &#39;iso9660&#39;
  17. artTemplate 原生 js 模板语法版
  18. 【MySQL】乐观锁和悲观锁
  19. PDF文本内容批量提取到Excel
  20. 【Javascript-基础-getOwnPropertyNames】Object.getOwnPropertyNames() 获取对象自身可枚举属性

热门文章

  1. 各种ESB产品比较(转)
  2. ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件
  3. [ACM] POJ 3686 The Windy&amp;#39;s (二分图最小权匹配,KM算法,特殊建图)
  4. nginx 日志和监控
  5. 【iOS开发-21】UINavigationController导航控制器初始化,导航控制器栈的push和pop跳转理解
  6. 【Leetcode】Partition List (Swap)
  7. Unity3d C# Socket 下载文件 (同步到)
  8. Linux学习笔记——如何使用共享库交叉编译
  9. Linux管道通信
  10. STL源代码分析--迭代摘要、迭代器失效汇总