53 条题解
-
2linshutan LV 3 @ 2008-10-22 08:52:50
道试题的数学性质很强,关键点在于“一个数与其约数”的关系。在设计算法之前,我们不妨先对“一个数与其约数”进行一番简单的分析。
先举个简单的例子,求一个数756的约数总个数。
大家都知道先将756分解质因子,得到756=22×33×71,再把三个指数加一连乘就是756约数的总个数[1]:(2+1)×(3+1)×(1+1)=24。
在本题中,所要求的是[1,N]范围内最大的反质数,实际上也就是要求约数个数最多的那个数[2]。那么,一个数最多会有多少个不同的质因子呢?最多又会有多少个约数呢?
粗略估算:2×3×5×7×11×13×17×19×23×29=6469693230>2×109。所以,我们就得到了一个很重要的性质:
性质一:在[1,2×109]中,一个数最多有10个不同的质因子。
根据经验,一个正整数N,其约数个数是 级的[3]。因此,我们又可以得到另一个重要性质:
性质二:在[1,2×109]中一个数其约数个数大致也就是104~105级别[4]。
这两个性质虽然是通过估算得出的,但其正确性是无庸质疑的。在以后的算法设计中,这两个性质将起着举足轻重的作用。
再回头看对正整数756的分析:756=22×33×71,共有24个约数。那么它是否是一个“反质数”呢?显然,我们可以构造出另一个正整数,也有24个约数,却比756要小:540=22×33×51。
构造反例的原理在于,756的质因子2、3、7不是连续的质数,漏了5,用5代替7,而指数不变就可以构造出一个更小的但有着相同约数个数的正整数。因此,我们又得到了一个关于“反质数”的性质:
性质三:一个反质数的质因子必然是从2开始连续的质数。
分析至此,对“一个数和其约数”,“反质数”我们已有了初步的了解,并且大致掌握了一些基础性质。下面,在这些分析的基础上,我们开始尝试着设计一个时间效率上能够被接受的算法。
算法设计
由于题目中N的范围很大——有2×109,所以想通过求出每个数约数的个数,最后通过统计找出最大的反质数,这种方法效率很低,是不现实的。我们必须另辟蹊径。
在[1, 2×109]中有很多数显然不是“反质数”,在先前的分析中,性质三就充分说明了这一点。
根据题目对“反质数”的定义,我们知道,不可能有两个反质数,其约数个数相同。那么,根据性质二,“反质数”的个数将远远小于2×109,而只是104到105级别。这样一来,我们就可以考虑直接产生所有的“反质数”,再从中找出最大的。
在先前的题意分析中,我们知道:“反质数”与一个数的约数总数,质因子总数都有着莫大的联系,不妨将这个因素放在一起。
设f(i,j)记录的是:约数总数为i,有j个不同的质因子的最小正整数。
显然,所有的“反质数”都出自f(i,j)。如果能计算出所有f(i,j),那么只要在其中扫描一遍,就可以得到问题的解了。现在的问题就转化成如何快速求出f(i,j)。
还是举个简单例子,假设f(12,3)=60,60=22×31×5。因此,f(6,2)一定为12,若f(6,2)小于12,我们可以用f(6,2)×5来代替原来f(12,3)中60的值。这正是关于f(i,j)的最优化原理——因此,可以用动态规划来求解!
经过上述分析,问题被揭开了神秘的面纱,顺着动态规划线索,我们可以从容的写出以下结论:
l 状态表示:
f(i,j)记录“约数总数为i,有j个不同的质因子的最小正整数”。
l 边界条件:
f(1,0)=1
l 状态转移方程:
假设p( j )记录的是第j大的质数。
f(i,j)=max of {f(i/k+1,j-1)*p^k(j)} 其中i mod (k+1)=0,p^k(j)
-
12018-11-04 01:23:09@
打表出奇迹
cpp
#include<cstdio>
using namespace std;
int ans[]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360,2001000000};
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i;i++)
{
if(ans[i]>n)
{
printf("%d",ans[i-1]);
return 0;
}
}
return 0;
}
-
12016-08-30 15:54:10@
水
var
i:longint;
p:array[1..11]of integer=(2,3,5,7,11,13,17,19,23,29,31);
n,ans,kans:qword;
function min(a,b:qword):qword;
begin
if a>b then exit(b)
else
exit(a);
end;
procedure dfs(x,y:longint;v,z:qword);
var
tmp:int64;
begin
if v>n then exit;
if z>=kans then begin
if kans=z then
ans:=min(ans,v)
else
ans:=v;
kans:=z;
if v=n then exit;
end;
tmp:=1;
for i:=1 to x do begin
tmp:=tmp*p[y];
dfs(i,y+1,v*tmp,z*(i+1));
if tmp>n then break;
end;
end;
begin
read(n);
dfs(100000,1,1,1);
write(ans);
end. -
12009-10-14 17:57:09@
话说这道题不大对……应该是输出最小的n以内含有最多因数的反质数。害的我WA掉了。。3次才AC够猥琐的。。。
还有就是为啥爆搜过不了呢?
编译通过...
├ 测试数据 01:答案错误... ├ 标准行输出 13967...
├ 错误行输出 14702...
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 56ms
---|---|---|---|---|---|---|---|-
Unaccepted 有效得分:90 有效耗时:56ms
(我是sunny)。。。囧是不是数据错了。。。事实上爆搜是可以的……
好猥琐的题目啊。。最后一个点还是cheat吧……
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms
(Orz Puppy)好了。。。AC了……虽然不是挂表但是一样秒杀。。。
讲一下做法吧……很简单,爆搜指数……
对于一个数n如果n=p1^q1*p2^q2*……*pk^qk
其中pi(0=q3>=q4>=……>=qk
然后爆搜解决……由于是这样的,2*3*5*7*11*13*17*23*29*31>2*10^9,所以最多用到这些质数。
好了一共9-10个质数,爆搜就可以了。。。Orz linshutan神牛的DP。。。
-
02017-05-08 12:33:31@
/* 数论题表示不懂 就直接贴个搜索的程序? 不要打表啊rp-- */ #include <iostream> #include <stdio.h> using namespace std; const int prime[16]= {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; long long ans=888888888888888,n; int bestsum; void work(long long num,int sum,int k) { if(sum>bestsum) { bestsum=sum; ans=num; } else if(sum==bestsum&&num<ans) { ans=num; } else if(sum<bestsum&&num>ans)return; if(k>15)return; long long total=num; for(int i=1;i<=50;i++) { if(total*prime[k]>n)break; total*=prime[k]; work(total,sum*(i+1),k+1); } } int main() { cin>>n; work(1,1,1); cout<<ans<<endl; return 0; }
-
02015-09-27 17:02:02@
###并不需要打表啊!
记录信息
评测状态 Accepted
题目 P1172 反质数
递交时间 2015-09-27 16:59:46
代码语言 C++
评测机 VijosEx
消耗时间 38 ms
消耗内存 516 KiB
评测时间 2015-09-27 16:59:47
评测结果
编译成功foo.cpp: In function 'int main()':
foo.cpp:29:17: warning: unknown conversion type character 'l' in format [-Wformat=]
scanf("%lld",&n);
^
foo.cpp:29:17: warning: too many arguments for format [-Wformat-extra-args]
foo.cpp:31:25: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("%lld\n",bestnum);
^
foo.cpp:31:25: warning: too many arguments for format [-Wformat-extra-args]
测试数据 #0: Accepted, time = 3 ms, mem = 512 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 516 KiB, score = 10
测试数据 #2: Accepted, time = 3 ms, mem = 512 KiB, score = 10
测试数据 #3: Accepted, time = 0 ms, mem = 512 KiB, score = 10
测试数据 #4: Accepted, time = 5 ms, mem = 512 KiB, score = 10
测试数据 #5: Accepted, time = 15 ms, mem = 512 KiB, score = 10
测试数据 #6: Accepted, time = 0 ms, mem = 512 KiB, score = 10
测试数据 #7: Accepted, time = 9 ms, mem = 512 KiB, score = 10
测试数据 #8: Accepted, time = 1 ms, mem = 516 KiB, score = 10
测试数据 #9: Accepted, time = 2 ms, mem = 512 KiB, score = 10
Accepted, time = 38 ms, mem = 516 KiB, score = 100
代码
#include <iostream>
#include <stdio.h>
using namespace std;
const int prime[16]= {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
long long bestnum=888888888888888,n;
int bestsum;void work(long long num,int sum,int k)
{
if(sum>bestsum){
bestsum=sum;
bestnum=num;
}
else if(sum==bestsum&&num<bestnum){
bestnum=num;
}
else if(sum<bestsum&&num>bestnum)return;
if(k>15)return;
long long total=num;
for(int i=1;i<=50;i++){
if(total*prime[k]>n)break;
total*=prime[k];
work(total,sum*(i+1),k+1);
}
}
int main()
{scanf("%lld",&n);
work(1,1,1);
printf("%lld\n",bestnum);
} -
02013-10-30 21:20:59@
打表— —
-
02013-10-04 00:54:31@
记录信息
评测状态 Accepted
题目 P1172 反质数
递交时间 2013-10-04 00:53:28
代码语言 C
评测机 VijosEx
消耗时间 0 ms
消耗内存 448 KiB
评测时间 2013-10-04 00:53:29评测结果
编译成功测试数据 #0: Accepted, time = 0 ms, mem = 440 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 444 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 444 KiB, score = 10
测试数据 #3: Accepted, time = 0 ms, mem = 448 KiB, score = 10
测试数据 #4: Accepted, time = 0 ms, mem = 436 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 444 KiB, score = 10
测试数据 #6: Accepted, time = 0 ms, mem = 444 KiB, score = 10
测试数据 #7: Accepted, time = 0 ms, mem = 444 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 440 KiB, score = 10
测试数据 #9: Accepted, time = 0 ms, mem = 444 KiB, score = 10
Accepted, time = 0 ms, mem = 448 KiB, score = 100
代码
#include <stdio.h>
int main (){
long n;
int i;
scanf ("%ld",&n);
long a[68]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360};
if (n>1396755360)
{printf ("1396755360\n");return 0;}
for (i=0;i<68;i++)
{if (a[i]>n)
{if (n<=0) {printf ("\n");break;}
else
{printf ("%ld\n",a[i-1]);break;}
}
}
return 0;
}
终于OK了!
从11:25到0:54^_^ -
02013-10-04 00:50:28@
测试数据 #0: WrongAnswer, time = 0 ms, mem = 532 KiB, score = 0
?????
-
02013-10-04 00:49:51@
评测结果
编译成功测试数据 #0: WrongAnswer, time = 0 ms, mem = 532 KiB, score = 0
测试数据 #1: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 544 KiB, score = 10
测试数据 #3: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #4: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #6: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #7: Accepted, time = 0 ms, mem = 540 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 532 KiB, score = 10
测试数据 #9: Accepted, time = 15 ms, mem = 540 KiB, score = 10
WrongAnswer, time = 15 ms, mem = 544 KiB, score = 90
代码
#include <stdio.h>
int main (){
long n;
int i;
scanf ("%ld",&n);
long a[68]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360};
for (i=0;i<68;i++)
{if (a[i]>n)
{if (n==0) {printf ("0\n");break;}
else
{printf ("%ld\n",a[i-1]);break;}
}
}
return 0;
}
#1是什么? -
02013-07-27 17:50:18@
var n,i:longint;
a:array[0..68]of longint;
begin
readln(n);
a[1]:=1;
a[2]:=2;
a[3]:=4;
a[4]:=6;
a[5]:=12;
a[6]:=24;
a[7]:=36;
a[8]:=48;
a[9]:=60;
a[10]:=120;
a[11]:=180;
a[12]:=240;
a[13]:=360;
a[14]:=720;
a[15]:=840;
a[16]:=1260;
a[17]:=1680;
a[18]:=2520;
a[19]:=5040;
a[20]:=7560;
a[21]:=10080;
a[22]:=15120;
a[23]:=20160;
a[24]:=25200;
a[25]:=27720;
a[26]:=45360;
a[27]:=50400;
a[28]:=55440;
a[29]:=83160;
a[30]:=110880;
a[31]:=166320;
a[32]:=221760;
a[33]:=277200;
a[34]:=332640;
a[35]:=498960;
a[36]:=554400;
a[37]:=665280;
a[38]:=720720;
a[39]:=1081080;
a[40]:=1441440;
a[41]:=2162160;
a[42]:=2882880;
a[43]:=3603600;
a[44]:=4324320;
a[45]:=6486480;
a[46]:=7207200;
a[47]:=8648640;
a[48]:=10810800;
a[49]:=14414400;
a[50]:=17297280;
a[51]:=21621600;
a[52]:=32432400;
a[53]:=36756720;
a[54]:=43243200;
a[55]:=61261200;
a[56]:=73513440;
a[57]:=110270160;
a[58]:=122522400;
a[59]:=147006880;
a[60]:=183783600;
a[61]:=245044800;
a[62]:=294053760;
a[63]:=367567200;
a[64]:=551350800;
a[65]:=698377680;
a[66]:=735134400;
a[67]:=1102701600;
a[68]:=1396755360;
for i:=68 downto 1 do if n>=a[i] then break;
writeln(a[i]);
end.
秒杀!爽!!只是列表列了半天…… -
02009-11-03 17:43:47@
一次AC乌啦啦,以前没咋搞懂这种题咋回事。现在却觉得这题越来越来水,于是会今天就把这题给水了。
---|---|---|---|---|---|---|---|---|---|--
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0msconst
num:array[1..10]of longint=(2,3,5,7,11,13,17,19,23,29);
maxnum=2000000000;
var
i,n,max,min:longint;
lim:array[0..11]of longint;
f:array[0..30,0..32]of longint;
function get(a,m:longint):longint;
begin
if f[a,m]min)and(b10 then
begin
if (b>max)or((b=max)and(a -
02009-09-20 11:45:54@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0msvar a:array[1..68]of longint=(1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,
1680,2520,5040,7560,
10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,
221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,
2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,
21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,
147026880,183783600,245044800,294053760,367567200,551350800,698377680,
735134400,1102701600,1396755360);
i,n:longint;
begin
readln(n);
for i:=1 to 68 do
if a[i]>n then
begin
writeln(a);halt;
end;
writeln(a[68]);
end.Flag Accepted
题号 P1172
类型(?) 数论 / 数值
通过 457人
提交 1010次
通过率 45%
难度 3打了一个小时的表,终于出解
-
02009-09-17 20:40:14@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms快速幂+DP
我竟然一次就AC了啊!!!!!
人品大爆发!!!!!!!!!!!! -
02009-09-07 21:32:03@
program p1172;
const
chart : array[1..69] of int64=
(1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,
1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,
50400,55440,83160,110880,166320,221760,277200,332640,498960,
554400,665280,720720,1081080,1441440,2162160,2882880,3603600,
4324320,6486480,7207200,8648640,10810800,14414400,17297280,
21621600,32432400,36756720,43243200,61261200,73513440,110270160,
122522400,147026880,183783600,245044800,294053760,367567200,
551350800,698377680,735134400,1102701600,1396755360, 20000000001);
var
n,i:longint;
begin
readln(n);
for i:=1 to 69 do if chart[i]>n then
begin
writeln(chart);halt;
end;
end.交表万岁
-
02009-08-18 20:20:46@
-
02009-07-30 10:20:45@
虽然有公式,但搜搜太烦,容易错,那表我运行了好久,终于诞生了。
交上去毫无悬念地过了。 -
02009-07-20 21:18:45@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms交表就是过瘾!!!
const a : array[1..68] of longint = ( 1,2,4,6,12,24,36,48,60,120,
180,240,360,720,840,1260,1680,2520,5040,7560,
10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,
166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,
2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,
21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,
245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360);
var
n,i,k:longint;
begin
readln(n);
if (1396755360 < n) and (2000000000 >= n) then writeln('1396755360')
else
begin
for i:= 1 to 68 do if a[i] > n then break;
writeln(a);
end;
end. -
02009-07-17 08:37:56@
爆搜没有好下场-_-!
编译通过...
├ 测试数据 01:运行时错误...| 错误号: 202 | 堆栈溢出错
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 478ms
├ 测试数据 07:运行超时...
├ 测试数据 08:运行超时...
├ 测试数据 09:运行时错误...| 错误号: 202 | 堆栈溢出错
├ 测试数据 10:运行时错误...| 错误号: 202 | 堆栈溢出错
---|---|---|---|---|---|---|---|-
Unaccepted 有效得分:50 有效耗时:478ms -
02009-07-08 23:38:48@
沙茶题留名……
这种题就是用来练习交表的……