永发信息网

NOI高手来...关于去年的NOIP第二题.

答案:3  悬赏:50  手机版
解决时间 2021-06-01 20:37
  • 提问者网友:火车头
  • 2021-06-01 12:08

  关于去年的第二题..~~~

   是数论吧..~~

  搜索+剪枝只能80... 

  哪位高手能来讲讲..`~~...

最佳答案
  • 五星知识达人网友:千杯敬自由
  • 2021-06-01 12:35
我就是传说中的高手····
全部回答
  • 1楼网友:第四晚心情
  • 2021-06-01 13:30
思路1: 根据最大公约数的定义,X必定为最大公约数的倍数,那么我们可以去枚举a1的倍数,然后去验证最大公约数和最小公倍数是否符合条件。期待分数:50。 程序1: var a0,a1,b0,b1,i,j,n,k,x,tot:longint; function gcd(a,b:longint):longint; begin if b=0 then exit(a) else exit(gcd(b,a mod b)); end; begin readln(n); for k:=1 to n do begin   tot:=0;   readln(a0,a1,b0,b1);   for i:=1 to (b1 div a1) do    begin     x:=i*a1;     if b1 mod x=0 then     if gcd(a0,x)=a1 then     if (b0*x) div (gcd(b0,x))=b1 then begin inc(tot); end;    end;   writeln(tot); end; end. 思路2: 根据最小公倍数和最大公约数分解质因数指数的特殊关系进行优化。比如两个数,分解质因数可以得到以下的式子 A=p1^a1+p2^a2+p3^a3…… B=p1^b1+p2^b2+p3^a3…… 例如6和21就可以分解成 6=2^1+3^1+5^0+7^0…… 21=2^0+3^1+5^0+7^1…… 则最大公约数=2^(min(a1,b1))+3^(min(a2,b2))+5^(min(a3,b3))+7^(min(a4,b4))… 最小公倍数=2^(max(a1,b1))+3^(max(a2,b2))+5^(max(a3,b3))+7^(max(a4,b4))… 那么我们可以先将b1分解质因数,在根据最大公约数和最小公倍数在指数上的关系,进行搜索。期待分数:100 程序2: var p,x,c:array[0..1000] of longint; a0,a1,b0,b1,i,j,k,m,tot,t,n:longint; function gcd(a,b:longint):longint; begin if b=0 then exit(a) else exit(gcd(b,a mod b)); end; procedure dfs(i,sum:longint); var max,j:longint; begin if i>m then begin   inc(tot);   p[tot]:=sum;   exit; end; max:=sum; dfs(i+1,max); for j:=1 to c[i] do begin   max:=max*x[i];   dfs(i+1,max); end; end; procedure work(b:longint); var i,p:longint; begin i:=2; p:=b; while i<=sqrt(p) do begin   if p mod i=0 then    begin     inc(m);     x[m]:=i;     c[m]:=0;     repeat     inc(c[m]);     p:=p div i;     until p mod i<>0;    end;   inc(i); end; if p<>1 then begin   inc(m);   x[m]:=p;   c[m]:=1; end; dfs(1,1); end; begin readln(n); for i:=1 to n do begin   readln(a0,a1,b0,b1);   fillchar(p,sizeof(p),0);   fillchar(x,sizeof(x),0);   fillchar(c,sizeof(c),0);   m:=0;   tot:=0;   t:=0;   work(b1);   for j:=1 to tot do   if (gcd(p[j],a0)=a1) and ((p[j] div gcd(p[j],b0) * b0)=b1) then inc(t);   writeln(t); end; end. 思路三: 和思路二有异曲同工之妙。我们可以先预处理trunc(sqrt(2000000000))以内的质数,然后每读入一组数据,初始答案ans=1,然后我们循环质数,看a0、a1、b0、b1里面有多少个该质数因子,并且将这四个数分别消去所有该质数因子。我们设求出来的该因子个数分别是t1、t2、t3、t4。如果数据合法,那么t1>=t2,t3<=t4。根据最大公约数和最小公倍数的定义,我们要求的数所拥有的该质因子个数s必须要同时满足以下限制条件: 若t1>t2,则s=t2 若t1=t2,则s>=t2 若t3<t4,则s=t4 若t3=t4,则s<=t4 这样,我们或者求出了s的范围,要么证明了不存在合法数字。如果s存在合法取值,我们就将ans乘上s的合法取值个数,否则直接输出0。 注意:如果循环结束后,a0>1或b1>1,那么此时a0或b1一定是超过我们枚举的数字范围的质数。这时我们特殊判断一下就行了。我们的时间复杂度是循环质数复杂度+分解因数复杂度。分解因数最坏是该数为2的若干次方,所以复杂度的上限是log(2000000000),很小。最慢的点在0.3秒以内出解。 程序3 program son; var i,j,k,l,m,n,p,q,l2,r2,r,s,t,a0,a1,b0,b1,ans:longint;     prime:array[0..60000] of longint;     need:array[0..60000] of longint;     pd:boolean; function pri(x:longint):boolean; var g:longint; begin   for g:=2 to trunc(sqrt(x)) do   if x mod g=0 then exit(false);   exit(true); end; begin   p:=1;prime[1]:=2;   for i:=3 to 50000 do if pri(i) then   begin     inc(p);     prime[p]:=i;   end;   read(n);   for t:=1 to n do   begin     read(a0,a1,b0,b1);     ans:=1;     fillchar(need,sizeof(need),255);     q:=p;     pd:=true;     for i:=1 to p do     begin     l:=0;r:=0;l2:=0;r2:=0;     while a0 mod prime[i]=0 do     begin     inc(l);a0:=a0 div prime[i];     end;     while a1 mod prime[i]=0 do     begin     inc(r);a1:=a1 div prime[i];     end;     while b0 mod prime[i]=0 do     begin     inc(l2);b0:=b0 div prime[i];     end;     while b1 mod prime[i]=0 do     begin     inc(r2);b1:=b1 div prime[i];     end;     if l>r then need[i]:=r;     if l2<r2 then     begin     if (need[i]>-1)and(need[i]<>r2) then     begin     pd:=false;break;     end;     need[i]:=r2;     end;     if need[i]=-1 then     if r2<r then     begin     pd:=false;break;     end else ans:=ans*(r2-r+1);     end;     if i=p then     if a0>1 then     begin     inc(i);prime[i]:=a0;     l:=0;r:=0;l2:=0;r2:=0;     while a0 mod prime[i]=0 do     begin     inc(l);a0:=a0 div prime[i];     end;     while a1 mod prime[i]=0 do     begin     inc(r);a1:=a1 div prime[i];     end;     while b0 mod prime[i]=0 do     begin     inc(l2);b0:=b0 div prime[i];     end;     while b1 mod prime[i]=0 do     begin     inc(r2);b1:=b1 div prime[i];     end;     if l>r then need[i]:=r;     if l2<r2 then     begin     if (need[i]>-1)and(need[i]<>r2) then     begin     pd:=false;     end;     need[i]:=r2;     end;     if need[i]=-1 then     if r2<r then     begin     pd:=false;     end else ans:=ans*(r2-r+1);         dec(i);     end;     if i=p then     if b1>1 then     begin     inc(i);prime[i]:=b1;     l:=0;r:=0;l2:=0;r2:=0;     while a0 mod prime[i]=0 do     begin     inc(l);a0:=a0 div prime[i];     end;     while a1 mod prime[i]=0 do     begin     inc(r);a1:=a1 div prime[i];     end;     while b0 mod prime[i]=0 do     begin         inc(l2);b0:=b0 div prime[i];     end;     while b1 mod prime[i]=0 do     begin     inc(r2);b1:=b1 div prime[i];     end;     if l>r then need[i]:=r;     if l2<r2 then     begin     if (need[i]>-1)and(need[i]<>r2) then     begin     pd:=false;     end;     need[i]:=r2;     end;     if need[i]=-1 then     if r2<r then     begin     pd:=false;     end else ans:=ans*(r2-r+1);     dec(i);     end;     if not pd then writeln(0) else writeln(ans);     end; end.
  • 2楼网友:酒者煙囻
  • 2021-06-01 13:18
【问题描述】 世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A 市对 所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根 据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第m*150% (向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有 选手。 现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成 绩。 【输入】 输入文件名为 score.in。 第一行,两个整数n,m(5 ≤ n ≤ 5000,3 ≤ m ≤ n),中间用一个空格隔开,其 中n 表示报名参加笔试的选手总数,m 表示计划录取的志愿者人数。输入数据保证m*150% 向下取整后小于等于n。 第二行到第 n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号k (1000 ≤ k ≤ 9999)和该选手的笔试成绩s(1 ≤ s ≤ 100)。数据保证选手的报名号各 不相同。 【输出】 输出文件 score.out。 第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为 进入面试的选手的实际人数。 从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手 的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的 顺序输出。 【输入输出样例】 score.in score.out 6 3 1000 90 3239 88 2390 95 7231 84 1005 95 1001 88 88 5 1005 95 2390 95 1000 90 1001 88 3239 88 【样例说明】 m*150% = 3*150% = 4.5,向下取整后为4。保证4 个人进入面试的分数线为88,但因为88 有重分,所以所有成绩大于等于88 的选手都可以进入面试,故最终有5 个人进入面试。 type rec=record num:longint; grade:longint; end; arraytype=array[1..5100] of rec; procedure qsort(var a:arraytype;lx,rx:longint); var i,j:longint; x,temp:rec; begin i:=lx; j:=rx; x:=a[random(j-i+1)+i]; while i<=j do begin while (a[i].grade>x.grade) or ((a[i].grade=x.grade) and (a[i].num<x.num)) do inc(i); while (a[j].grade<x.grade) or ((a[j].grade=x.grade) and (a[j].num>x.num)) do dec(j); if i<=j then begin temp:=a[i]; a[i]:=a[j]; a[j]:=temp; inc(i); dec(j); end; end; if i<rx then qsort(a,i,rx); if j>lx then qsort(a,lx,j); end; var a:arraytype; n,m,i,luquxian,d:longint; begin assign(input,'score.in'); assign(output,'score.out'); reset(input); rewrite(output); read(n,m); for i:=1 to n do read(a[i].num,a[i].grade); qsort(a,1,n); m:=trunc(m*3/2); luquxian:=a[m].grade; for i:=1 to n do if a[i].grade>=luquxian then inc(d); writeln(luquxian,' ',d); for i:=1 to n do if a[i].grade>=luquxian then writeln(a[i].num,' ',a[i].grade); close(input); close(output); end.
我要举报
如以上回答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
点此我要举报以上问答信息
大家都在看
推荐资讯