hdu5908 Abelian Period 暴力 小小小小的优化
来源:互联网 发布:js return void 编辑:程序博客网 时间:2024/05/22 11:23
题目链接
这道题是昨天晚上(10.1)的 bestcoder #88 的1002题,一开始交的时候(小数据)过了,最后还是崩了...
想想算法没问题啊,从1到n/2枚举可能的k,对于 未在之前的过程中被确认为可以的 并且 整除n的k 去判断是否可以。
判断的过程就是首先在第一段即0-k-1的区间中记录下各个数字出现的次数,然后对于之后的每一个i*k-i*k+k-1去判断是否和第一段相符,一旦出现矛盾就跳出来。
对于任意一个符合条件的k,它的整数倍(如果也整除n的话)都是符合条件的,这一点是很显然的,那么标记一下,省去后面的判断(就类似于素数筛法里面做的那样)。
好像也想不到什么其他的好方法了,能够改动的都是一些细节部分啊......可是就是TLE了。
TLE代码如下:
//1002.cpp#include <iostream>#include <climits>#include <cmath>#include <cstring>using namespace std;#define maxn 100010int a[maxn],tot[maxn],tott[maxn];bool exist[maxn];int main(){ int T,n,minn,maxx,i,j,k; bool flag; cin >> T; while (T--) { cin >> n; maxx = 0; minn = INT_MAX; for (i=0;i<n;++i) { cin >> a[i]; maxx = max(maxx,a[i]); minn = min(minn,a[i]); } memset(exist,0,sizeof(exist)); for (i=1;i<=n/2;++i) { if (exist[i] || n%i!=0) continue; memset(tot,0,sizeof(tot)); memset(tott,0,sizeof(tott)); for (j=0;j<i;j++) ++tot[a[j]]; for (j=1;j<n/i;++j) { flag = true; for (k=minn;k<=maxx;++k) tott[k] = tot[k]; for (k=j*i;k<j*i+i;++k) --tott[a[k]]; for (k=minn;k<=maxx;++k) if (tott[k]!=0) { flag = false; break; } if (!flag) break; } if (flag) { j = 1; while (i*j<=n) { if (n%(i*j)==0) exist[i*j] = true; ++j; } } } for (i=1;i<n;++i) if (exist[i]) cout << i << " "; cout << n << endl; } return 0;}
那么既然这样的话就稍微改动一下细节吧。
上面的写法花了很多时间在无用元素的处理上(对本身就不存在的元素去判断是不是0)和每次判断一个k是否可行的时候都要做的两个memset。
既然这样的话就在这里处理一下吧,加一个数组去记录需要对哪些进行判断,需要对哪些最后清零。
然后这样就过了。
没错就是改进了这个地方然后就过了。
其实还有其他地方可以小小改进,比如说判断的k的范围,对每个数字出现的次数进行统计,可能分成的段数肯定小于等于它们的gcd;在这个基础上直接用总的个数/分的段数得到每个数字出现的次数,也就没有必要去单独拿出第一段统计了(其实也差不多...)
AC代码如下:
//1002.cpp#include <iostream>#include <climits>#include <cmath>#include <cstring>using namespace std;#define maxn 100010int a[maxn],tot[maxn],tott[maxn],in[maxn];bool exist[maxn];int main(){ int T,n,minn,maxx,i,j,k,t,kk; bool flag; cin >> T; while (T--) { cin >> n; maxx = 0; minn = INT_MAX; for (i=0;i<n;++i) cin >> a[i]; memset(exist,0,sizeof(exist)); memset(tot,0,sizeof(tot)); for (i=1;i<=n/2;++i) { if (exist[i] || n%i!=0) continue; t = 0; for (j=0;j<i;++j) { ++tot[a[j]]; in[t++] = a[j]; } for (j=1;j<n/i;++j) { flag = true; for (k=0;k<t;++k) tott[in[k]] = tot[in[k]]; for (k=j*i;k<j*i+i;++k) --tott[a[k]]; for (k=0;k<t;++k) if (tott[in[k]]!=0) { for (kk=0;kk<t;++kk) tot[in[kk]] = 0; flag = false; break; } if (!flag) break; } if (flag) { j = 1; while (i*j<=n) { if (n%(i*j)==0) exist[i*j] = true; ++j; } } } for (i=1;i<n;++i) if (exist[i]) cout << i << " "; cout << n << endl; } return 0;}
感觉有点小悲伤,就是因为这一点点的差别,直接导致了TLE,1002就没分了。
1001也是死在了细节上面,其中一步是
sum += (tot+1)*tot/2;
tot开的是int(因为tot的最大值是100000),sum开的是long long,以为可以类型转换过去的(蠢了...),然后就跪了。显然不可以啊,int*int再怎么也不会转化到long long去啊。
于是1001就在hack阶段给别人做出了贡献...明明是这么简单的题却就又没分了。
觉得这个错误纯粹是缺乏经验,再加上想当然了一下并且偷了个懒,只要把tot开成long long或者是写成 sum += (long long)(tot+1)*tot/2; 就可以了啊...
表示一下小心痛,以后会在这些地方多加注意的。
宝贵的经验教训啊。
- hdu5908 Abelian Period 暴力 小小小小的优化
- HDU5908 Abelian Period(模拟暴力)
- HDU5908-Abelian Period
- hdu5908 Abelian Period (water)
- HDU5908 Abelian Period
- hdu 5908 Abelian Period(暴力 + map优化)
- 【HDU 5908 || #bestcoder88 1002】【map的应用 暴力】Abelian Period
- hdu 5908 Abelian Period【思维+暴力枚举】
- HDU 5908 Abelian Period(暴力)
- HDU-5908-Abelian Period(暴力)
- HDU 5908 Abelian Period (暴力+map)
- HDU -- 5908 Abelian Period 【思维 + map + 暴力】
- php优化的小小细节
- 一些小小的时间优化
- Abelian Period
- Abelian Period
- 小小
- 关于Android优化的小小细节
- Ubuntu 界面美化
- UML中常见代码实现
- eclipse设置代码自动提示
- [闲聊]搜索素数的一个方法
- elasticsearch 重启后,需要的操作
- hdu5908 Abelian Period 暴力 小小小小的优化
- opencv 学习之 图像色偏、清晰度、亮度检测
- 序列号SYN+确认号ACK
- 22
- OpenGL学习脚印:几何着色器(geometry shader)
- 正则表达式(1)---JavaScript
- ubuntu创建桌面快捷方式步骤和注意事项
- 淘淘商城的实践(3)——图片服务器部署和前台工程
- 【DP】 noi openjudge 2.6 山区建小学