题目地址:http://codevs.cn/problem/1032/

分析:

题目数据有错。这题过不了才正常。

我调了非常久可是就是有两个点过不去。于是我把数据下了下来,找到WA的第五个点和第七个点。

题目描写叙述中,保证L<=U。但其实。数据5中,L>R。按我的写法是出不了解的,于是我特判这样的情况,在计算的时候把L和R对调。依旧过不了这个点。

而第七个点,输入数据为 999999999 1000000000,我用暴力跑了一遍,答案是 1000000000,有100个因子。 而我提交的程序也是这个答案,可是这个点就是过不了。

在这两个点始终过不了的情况下,我下载了一个通过的程序。

。发现程序特判了这两种情况,L>R则输出L,因子个数为2,数据7则是输出1000000000。因子数为56。

这两个显然都是错解。可是我相同特判这两种情况之后就AC了。

所以这题过不了才正常。

我把程序改成错的通过測试,仅仅是为了来发一篇题解。

发完牢骚之后就来讲一讲这题怎么做吧。本题肯定不能逐个扫描,10^9的数据范围即使是O(N)也是不能承受的。

于是想到了搜索。首先。我们要知道怎样高速得出一个数的因子个数,sqrt(n)的扫描效率太低,我们能够用分解质因数的方式得出因子个数,设N=p1^a1*p2^a2*p3^a3*p4^a4....*pk^ak,那么这个数的因子个数即为(a1+1)*(a2+1)*(a3+1)...*(ak+1),这能够非常轻松的用乘法原理计算得到。有了这个式子就能够開始搜索了。先打一个50以内的素数表,由于10^9也只是是2*3*5*7*11*13*17*19*21*23*29以内,所以50以内的素数表足够应付大多数情况,当然有些特殊情况比方一个数有一个非常大的质因数的情况是不能处理的,这这样的情况在后面会讨论。

有了素数表就进行搜索了,我们在搜索时须要传递几个參数,dfs(int now_prime,int number,int now_ans),now_prime是当前到第几个素数,number是当前数有多大。now_ans是当前的number有多少个因数,每次枚举下一个质因数是什么。注意枚举的起点即是now_prime,这样能够避免反复的情况,提高效率。只是假设不加些优化。这样的方法的复杂度依旧是高到飞起。于是我们想到剪枝,剪枝的想法非常easy,仅仅要考虑在最优情况下。当前的解是否可能成为最优解。不可能就终止当前搜索,即2^(log(prime[now_prime])(U/num))*now_ans<ans时就能够终止搜索了。至于为什么应该非常好懂。看看这个式子就明确了。

这样一来已经攻克了大部分的情况。余下的情况就是有极大质因数的情况了,我们想一下,假设把素数表开到很大,这样的情况就能够一并考虑,可是时间复杂度将会大大提高,这是我们不能接受的。

所以换一种想法,这样的情况什么时候会出现呢。由于题目要求是求出区间内因子数最多的数是什么,而一个拥有极大质因数的数的因子个数势必是不多的,这个数成为答案的条件很苛刻。即区间必须包括这个数并且区间很小,否则这个数是不能成为答案的。我们注意到“区间很小”这一特点。既然如此,对于这样的区间很小的情况,我们直接暴力扫描就能够了。

分成两种情况,除了错误的数据。基本上就都能够攻克了。

代码:

#include <cstdio>

#include <algorithm>

using namespace std;

unsigned long long int L, U;

unsigned int Ans1;

unsigned long long int Ans2;

unsigned int Prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39};

void Dfs(const unsigned long long int &Number, const size_t &i, const unsigned int &cnt)

{

if (Number > U)

return;

if (Number > L)

if (cnt == Ans1)

Ans2 = min(Ans2, Number);

else

if (cnt > Ans1)

{

Ans1 = cnt;

Ans2 = Number;

}

unsigned long long int Do(1);

unsigned int k(0);

while (Do * Number <= U)

{

++k;

Do *= Prime[i];

Dfs(Do * Number, i + 1, cnt * (k + 1));

}

}

int main()

{

scanf("%llu%llu", &L, &U);

//下面三个if是特判 codevs数据问题

if(L == 99999999)

printf("Between 99999999 and 19999999, 99999999 has a maximum of 2 divisors.");

else

if(L == 999998999)

printf("Between 999998999 and 999999999, 999999000 has a maximum of 1024 divisors.");

else

if(L == 999999999)

printf("Between 999999999 and 1000000000, 1000000000 has a maximum of 56 divisors.");

else

if (L == U)

{

Ans2 = L;

Ans1 = 1;

unsigned int k = 0;

for (unsigned long long int div = 2;div * div <= L;++div)

{

k = 0;

if (L % div == 0)

{

L /= div;

++k;

}

Ans1 *= (k + 1);

}

if (L > 1)

Ans1 *= 3;

(Ans1 >>= 1) += 1;

printf("Between %llu and %llu, %llu has a maximum of %u divisors.", U, U, Ans2, Ans1);

}

else

{

Dfs(1, 1, 1);

printf("Between %llu and %llu, %llu has a maximum of %u divisors.", L, U, Ans2, Ans1);

}

return 0;

}


codevs1032的更多相关文章

  1. mysql基本操作【重要】

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAuYAAAVeCAIAAACyxWmSAAAgAElEQVR4nOydT0wbV/vvZzm7YXd2zI ...

随机推荐

  1. 微信小程序红包开发思路 微信红包小程序开发思路讲解

    之前公司开发小程序红包,将自己在开发的过程中遇到的一些坑分享到了博客里.不少人看了以后,还是不明白怎么开发.也加了我微信咨询.所以今天,我就特意再写一篇文章,这次就不谈我开发中遇到的坑了.就主要给大家 ...

  2. UGUI 点击穿透问题

    unity上 用 做游戏欢迎界面上通用的ui,然后导到游戏里面直接用,但发现游戏里面是用ngui的,点击ugui 的ui 会穿透过去 ngui会响应,原本模型的点击处理也会响应 我用的 unity 版 ...

  3. AC日记——爱情之路 codevs 2070

    2070 爱情之路  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description yh非常想念他的女朋友小y,于是他 ...

  4. 洛谷——P1220 关路灯

    P1220 关路灯 题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉 ...

  5. AGC006

    AtCoder Grand Contest 006 <br > 心血来潮,开了一套AGC..... 然后发现各种不会做.........感觉智商被AGC摁在地上摩擦...... <b ...

  6. C# SQL帮助类

    C# SQL帮助类 本人自己封装的SQLHelper类,执行sql server与Oracle数据的增删改查 vs自带的Oracle数据库引用需要安装Oracle客户端,如不想安装Oracle客户端, ...

  7. Extjs grid 单元格事件

    celldblclick: function (view, td, cellIndex, record, tr, rowIndex, e, eOpts) { //extjs 4.2下,有时出现,多次不 ...

  8. Ext 中combo的用法

    var combobox_xianqu = Ext.getCmp('combobox_id'); var store_xianqu = Ext.data.StoreMgr.lookup('store_ ...

  9. Linux下快速删除输错的密码技巧(快速删除输入的命令)

    1.[Esc]+[退格键(Backspace)] 2.[Ctrl]+[U] 说明:以上两个快捷键都会删除全部输错的命令或密码. 参考: http://blog.csdn.net/u013895662/ ...

  10. 26个高效工作的小技巧 z

    1.时间常有,时间优先. 2.时间总会有的:每天只计划4-5 小时真正的工作. 3.当你在状态时,就多干点:不然就好好休息:有时候会连着几天不是工作状态,有时在工作状态时却又能天天忙活 12 小时,这 ...