NOIP2009 pj
A
1.多项式输出
(poly.pas/c/cpp)
【问题描述】
一元 n 次多项式可用如下的表达式表示:
1 0
1
1 f (x) a x a xn ... a x a
n
n
n = + − + + +
− , ≠ 0 n a
其中,
i
i a x 称为i 次项, i a 称为i 次项的系数。给出一个一元多项式各项的次数和系
数,请按照如下规定的格式要求输出该多项式:
1. 多项式中自变量为x,从左到右按照次数递减顺序给出多项式。
2. 多项式中只包含系数不为0 的项。
3. 如果多项式n 次项系数为正,则多项式开头不出现“+”号,如果多项式n 次项系
数为负,则多项式以“-”号开头。
4. 对于不是最高次的项,以“+”号或者“-”号连接此项与前一项,分别表示此项
系数为正或者系数为负。紧跟一个正整数,表示此项系数的绝对值(如果一个高于0 次的项,
其系数的绝对值为1,则无需输出1)。如果x 的指数大于1,则接下来紧跟的指数部分的形
式为“x^b”,其中b 为x 的指数;如果x 的指数为1,则接下来紧跟的指数部分形式为“x”;
如果x 的指数为0,则仅需输出系数即可。
5. 多项式中,多项式的开头、结尾不含多余的空格。
【输入】
输入文件名为 poly.in,共有2 行
第一行 1 个整数,n,表示一元多项式的次数。
第二行有 n+1 个整数,其中第i 个整数表示第n-i+1 次项的系数,每两个整数之间用空
格隔开。
【输出】
输出文件 poly.out 共1 行,按题目所述格式输出多项式。
【输入输出样例 1】
poly.in poly.out
5
100 -1 1 -3 0 10
100x^5-x^4+x^3-3x^2+10
【输入输出样例2】
poly.in poly.out
3
-50 0 0 1
-50x^3+1
【数据范围】
1 ≤ n ≤ 100,多项式各次项系数的绝对值均不超过100。
Solution
很坑的模拟,比赛时没注意到细节爆零。。。
1 program test; 2 const 3 inf='poly.in'; 4 outf='poly.out'; 5 6 var 7 n,i,j:longint; 8 a:array[1..100] of longint; 9 boo:boolean; 10 11 procedure wr(apple:longint); //process one!. 12 begin 13 if apple<0 then write('-') 14 else if boo then write('+'); 15 apple:=abs(apple); boo:=true; 16 if apple=1 then exit; 17 write(apple); 18 end; 19 20 begin 21 assign(input,inf); assign(output,outf); 22 reset(input); rewrite(output); 23 24 readln(n); boo:=false; 25 26 for i:= 1 to n+1 do 27 read(a[i]); 28 29 for i:= n downto 1 do 30 if a[n-i+1]<>0 then 31 begin 32 if (i=n) and (a[n-i+1]>0) then wr(abs(a[n-i+1])) 33 else wr(a[n-i+1]); 34 write('x'); 35 if (i>1) then write('^',i); 36 end; 37 if a[n+1]>0 then write('+'); 38 if a[n+1]<>0 then write(a[n+1]); 39 close(input); close(output); 40 end.
B
2.分数线划定
(score.pas/c/cpp)
【问题描述】
世博会志愿者的选拔工作正在 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 个人进入面试。
Solution
双子段的快排考试时卡壳
于是先排序然后对相同的分段排序
但是由于提交文件为test.pas, 爆零!
1 program test; 2 type 3 arr=array[1..5000] of longint; 4 5 const 6 inf='score.in'; 7 outf='score.out'; 8 9 var 10 n,m,i,temp,l,j:longint; 11 a,b:arr; 12 13 procedure qsort(var a,b:arr; l,r: longint); 14 var 15 i,j,x,y: longint; 16 begin 17 i:=l; j:=r; x:=a[(l+r) div 2]; 18 repeat 19 while a[i]<x do inc(i); 20 while x<a[j] do dec(j); 21 if not(i>j) then 22 begin 23 if not((a[i]=a[j]) and (b[i]>b[j])) then 24 begin 25 y:=a[i]; a[i]:=a[j]; a[j]:=y; 26 y:=b[i]; b[i]:=b[j]; b[j]:=y; 27 end; 28 inc(i); dec(j); 29 end; 30 until i>j; 31 if l<j then qsort(a,b,l,j); 32 if i<r then qsort(a,b,i,r); 33 end; 34 35 begin 36 assign(input,inf); assign(output,outf); 37 reset(input); rewrite(output); 38 39 readln(n,m); 40 for i:= 1 to n do 41 readln(a[i],b[i]); 42 43 qsort(b,a,1,n); 44 45 m:=trunc(m*1.5); 46 temp:=b[n-m+1]; 47 48 i:=n-m; 49 while b[i]>=temp do 50 begin 51 inc(m); dec(i); 52 if i=0 then break; 53 end; 54 55 writeln(temp,' ',m); 56 57 l:=n; 58 for i:= n-1 downto n-m do //n-m!!! =n-m+1-1 59 if b[i]<>b[i+1] then 60 begin 61 qsort(a,b,i+1,l); 62 for j:=i+1 to l do writeln(a[j],' ',b[j]); 63 l:=i; 64 end; 65 66 close(input); close(output); 67 end.
附上双字段快排版:
1 program no; 2 var 3 n,m,i:longint; 4 a,b:array[1..5000] of longint; 5 6 procedure qsort(l,r: longint); 7 var 8 i,j,x,y,o: longint; 9 begin 10 i:=l; j:=r; 11 x:=a[(l+r) div 2]; 12 o:=b[(l+r) div 2]; //!!!!!!!!!!! 13 repeat 14 while (a[i]<x) or ((a[i]=x) and (b[i]>o)) do inc(i); //!!!!!!!!!!! 15 while (x<a[j]) or ((a[j]=x) and (o>b[j])) do dec(j); //!!!!!!!!!!! 16 if not(i>j) then 17 begin 18 y:=a[i]; a[i]:=a[j]; a[j]:=y; 19 y:=b[i]; b[i]:=b[j]; b[j]:=y; //!!!!!!!!!!! 20 inc(i); j:=j-1; 21 end; 22 until i>j; 23 if l<j then qsort(l,j); 24 if i<r then qsort(i,r); 25 end; 26 27 begin 28 //assign(input,'t.in'); reset(input); 29 readln(n,m); m:=trunc(m*1.5); 30 for i:= 1 to n do 31 read(b[i],a[i]); 32 qsort(1,n); 33 34 for i:= n-m downto 1 do 35 if a[i]<>a[i+1] then break 36 else inc(m); 37 writeln(a[n-m+1],' ',m); 38 39 for i:= n downto n-m+1 do writeln(b[i],' ',a[i]); 40 close(input); 41 end.
C
3.细胞分裂
(cell.pas/c/cpp)
【问题描述】
Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家。现在,他正在为一个细胞实
验做准备工作:培养细胞样本。
Hanks 博士手里现在有N 种细胞,编号从1~N,一个第i 种细胞经过1 秒钟可以分裂为
Si 个同种细胞(Si 为正整数)。现在他需要选取某种细胞的一个放进培养皿,让其自由分裂,
进行培养。一段时间以后,再把培养皿中的所有细胞平均分入M 个试管,形成M 份样本,
用于实验。Hanks 博士的试管数M 很大,普通的计算机的基本数据类型无法存储这样大的
M 值,但万幸的是,M 总可以表示为m1 的m2 次方,即2
1
M = m m ,其中m1,m2均为基本
数据类型可以存储的正整数。
注意,整个实验过程中不允许分割单个细胞,比如某个时刻若培养皿中有4 个细胞,
Hanks 博士可以把它们分入2 个试管,每试管内2 个,然后开始实验。但如果培养皿中有5
个细胞,博士就无法将它们均分入2 个试管。此时,博士就只能等待一段时间,让细胞们继
续分裂,使得其个数可以均分,或是干脆改换另一种细胞培养。
为了能让实验尽早开始,Hanks 博士在选定一种细胞开始培养后,总是在得到的细胞“刚
好可以平均分入M 个试管”时停止细胞培养并开始实验。现在博士希望知道,选择哪种细
胞培养,可以使得实验的开始时间最早。
【输入】
输入文件名为 cell.in,共有三行。
第一行有一个正整数 N,代表细胞种数。
第二行有两个正整数 m1,m2,以一个空格隔开, 2
1
m m 即表示试管的总数M。
第三行有 N 个正整数,第i 个数Si 表示第i 种细胞经过1 秒钟可以分裂成同种细胞的个
数。
【输出】
输出文件 cell.out 共一行,为一个整数,表示从开始培养细胞到实验能够开始所经过的
最少时间(单位为秒)。
如果无论 Hanks 博士选择哪种细胞都不能满足要求,则输出整数-1。
【输入输出样例 1】
cell.in cell.out
1
2 1
3
-1
【输入输出样例1 说明】
经过 1 秒钟,细胞分裂成3 个,经过2 秒钟,细胞分裂成9 个,……,可以看出无论怎么分
裂,细胞的个数都是奇数,因此永远不能分入2 个试管。
【输入输出样例 2】
cell.in cell.out
2
24 1
30 12
2
【输入输出样例2 说明】
第 1 种细胞最早在3 秒后才能均分入24 个试管,而第2 种最早在2 秒后就可以均分(每
试管144/(241)=6 个)。故实验最早可以在2 秒后开始。
【数据范围】
对于 50%的数据,有2
1
m m ≤ 30000。
对于所有的数据,有1 ≤N≤ 10000,1 ≤m1 ≤ 30000,1 ≤m2 ≤ 10000,1 ≤ Si ≤ 2,000,000,000。
Solution
鄙人数论差。。。模拟也差。。。。
但是我们可以分解质因数
首先知道,如果第I种细胞分裂的最终结果能被M整除,那么他一定包含M的所有质因子
就是说最终的分裂得到的结果中同个质因子的个数一定大于等于M中对应的质因子的个数(即m[i])否则无论怎么分裂都不可能!
下面计算可能的分裂次数
所以我们先把M因式分解,怎么分解?枚举质因子,质因子怎么来?筛(即prim[i]表示从2开始的第I个质数)。。。。
然后把每一个S[I]因式分解,因为(s[i])^n得到的同个质因子的个数应该是s[i]中对应的质因子的个数的n倍
那么用m[i] div s[i]中包含的prim[i]这个质因子的个数apple得到变换次数,
注意如果m[i] /s[i]有余数就还要再多一次方
1 program cell; 2 const 3 inf='cell.in'; 4 outf='cell.out'; 5 type 6 arr=array[1..4500] of longint; 7 var 8 n,m1,m2,i,j,ans,tot,apple,ttt,k,y:longint; 9 ff:boolean; 10 prim,m:arr;//!!!!!!!!!1 11 b:array[2..40000] of boolean; 12 13 function min(aa,bb:longint):longint; 14 begin 15 if aa<bb then exit(aa) 16 else exit(bb); 17 end; 18 19 procedure shai; 20 var 21 nn,i,j:longint; 22 begin 23 fillchar(b,sizeof(b),true); 24 nn:=40000; 25 for i:= 2 to nn do 26 if b[i] then 27 begin 28 inc(tot); 29 prim[tot]:=i; 30 for j:= 1 to nn div i do 31 if b[i*j] then b[i*j]:=false; 32 end; 33 end; 34 35 procedure fenjie(var m:arr; apple:longint); 36 var 37 i:longint; 38 begin 39 for i:= 1 to tot do 40 begin 41 while (apple mod prim[i]=0) do 42 begin 43 m[i]:=m[i]+1; 44 apple:=apple div prim[i]; 45 end; 46 m[i]:=m[i]*m2; 47 end; 48 end; 49 50 procedure outgo; 51 begin 52 53 close(input); close(output); 54 halt; 55 56 end; 57 58 begin 59 assign(input,inf); assign(output,outf); 60 reset(input); rewrite(output); 61 62 readln(n); 63 readln(m1,m2); 64 if m1=1 then begin 65 writeln(0); 66 outgo; 67 end; 68 69 shai; 70 fenjie(m,m1); 71 ans:=maxlongint; 72 73 for j:= 1 to n do 74 begin 75 read(apple); 76 k:=0; ff:=true; 77 for i:= 1 to tot do 78 if m[i]>0 then 79 begin 80 if apple mod prim[i]<>0 then begin 81 ff:=false; 82 break; 83 end 84 else begin 85 ttt:=0; 86 while apple mod prim[i]=0 do 87 begin 88 inc(ttt); 89 apple:=apple div prim[i]; 90 end; 91 92 if m[i] mod ttt<>0 then y:=1 else y:=0; 93 ttt:=m[i] div ttt+y; 94 95 end; 96 if ttt>k then k:=ttt; 97 end; 98 if ff then ans:=min(ans,k); 99 end; 100 101 if ans<>maxlongint then writeln(ans) 102 else writeln(-1); 103 outgo; 104 105 end.
D
4.道路游戏
(game.pas/c/cpp)
【问题描述】
小新正在玩一个简单的电脑游戏。
游戏中有一条环形马路,马路上有n 个机器人工厂,两个相邻机器人工厂之间由一小段
马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这n 个机器人工厂编号为
1~n,因为马路是环形的,所以第n 个机器人工厂和第1 个机器人工厂是由一段马路连接在
一起的。小新将连接机器人工厂的这n 段马路也编号为1~n,并规定第i 段马路连接第i 个
机器人工厂和第i+1 个机器人工厂(1 ≤ i ≤ n-1),第n 段马路连接第n 个机器人工厂和第1
个机器人工厂。
游戏过程中,每个单位时间内,每段马路上都会出现一些金币,金币的数量会随着时间
发生变化,即不同单位时间内同一段马路上出现的金币数量可能是不同的。小新需要机器人
的帮助才能收集到马路上的金币。所需的机器人必须在机器人工厂用一些金币来购买,机器
人一旦被购买,便会沿着环形马路按顺时针方向一直行走,在每个单位时间内行走一次,即
从当前所在的机器人工厂到达相邻的下一个机器人工厂,并将经过的马路上的所有金币收集
给小新,例如,小新在i(1 ≤ i ≤ n)号机器人工厂购买了一个机器人,这个机器人会从i 号
机器人工厂开始,顺时针在马路上行走,第一次行走会经过i 号马路,到达i+1 号机器人工
厂(如果i=n,机器人会到达第1 个机器人工厂),并将i 号马路上的所有金币收集给小新。
游戏中,环形马路上不能同时存在2 个或者2 个以上的机器人,并且每个机器人最多能
够在环形马路上行走p 次。小新购买机器人的同时,需要给这个机器人设定行走次数,行走
次数可以为1~p 之间的任意整数。当马路上的机器人行走完规定的次数之后会自动消失,小
新必须立刻在任意一个机器人工厂中购买一个新的机器人,并给新的机器人设定新的行走次
数。
以下是游戏的一些补充说明:
1. 游戏从小新第一次购买机器人开始计时。
2. 购买机器人和设定机器人的行走次数是瞬间完成的,不需要花费时间。
3. 购买机器人和机器人行走是两个独立的过程,机器人行走时不能购买机器人,购买
完机器人并且设定机器人行走次数之后机器人才能行走。
4. 在同一个机器人工厂购买机器人的花费是相同的,但是在不同机器人工厂购买机器
人的花费不一定相同。
5. 购买机器人花费的金币,在游戏结束时再从小新收集的金币中扣除,所以在游戏过
程中小新不用担心因金币不足,无法购买机器人而导致游戏无法进行。也因为如此,
游戏结束后,收集的金币数量可能为负。
现在已知每段马路上每个单位时间内出现的金币数量和在每个机器人工厂购买机器人
需要的花费,请你告诉小新,经过m 个单位时间后,扣除购买机器人的花费,小新最多能
收集到多少金币。
【输入】
输入文件名为 game.in。
第一行 3 个正整数,n,m,p,意义如题目所述。
接下来的 n 行,每行有m 个正整数,每两个整数之间用一个空格隔开,其中第i 行描
述了i 号马路上每个单位时间内出现的金币数量(1 ≤ 金币数量≤ 100),即第i 行的第j
(1 ≤ j ≤m)个数表示第j 个单位时间内i 号马路上出现的金币数量。
最后一行,有 n 个整数,每两个整数之间用一个空格隔开,其中第i 个数表示在i 号机
器人工厂购买机器人需要花费的金币数量(1 ≤ 金币数量≤ 100)。
【输出】
输出文件 game.out 共一行,包含1 个整数,表示在m 个单位时间内,扣除购买机器人
花费的金币之后,小新最多能收集到多少金币。
【输入输出样例】
game.in game.out
2 3 2
1 2 3
2 3 4
1 2
5
【数据范围】
对于 40%的数据,2 ≤ n ≤ 40,1 ≤m≤ 40。
对于 90%的数据,2 ≤ n ≤ 200,1 ≤m≤ 200。
对于 100%的数据,2 ≤ n ≤ 1000,1 ≤m≤ 1000,1 ≤ p ≤m。
Solution
用f[i]表示到了第i秒时最优结果
于是f[i]=max{f[i-k]-spend[j]+这一次获得的价值,f[i]| 1<=i<=m; 1<=j<=n ;1<=k<=min(i,p)}
i 是时间,J 是此时终点, k 是这次走的长度
这一次获得的价值刚开始想用前缀和然后没有做出来
结果所以只需要在循环时用s来记录就可以啦
时间复杂度O(NMP)左右。。
1 program test; 2 const 3 inf='game.in'; 4 outf='game.out'; 5 6 var 7 n,m,i,j,p,k,s,y:longint; 8 jz:array[1..1000,1..1000] of longint; 9 spend,f:array[0..1000] of longint; 10 11 function max(aa,bb:longint):longint; 12 begin 13 if aa<bb then exit(bb) 14 else exit(aa); 15 end; 16 17 function min(aa,bb:longint):longint; 18 begin 19 if aa<bb then exit(aa) 20 else exit(bb); 21 end; 22 23 begin 24 assign(input,inf); assign(output,outf); 25 reset(input); rewrite(output); 26 27 readln(n,m,p); 28 for i:= 1 to n do 29 for j:= 1 to m do 30 read(jz[i,j]); 31 for i:= 1 to n do read(spend[i]); 32 33 for i:= 1 to m do 34 for j:= 1 to n do 35 begin 36 y:=j; 37 s:=0; 38 for k:= 1 to min(i,p) do 39 begin 40 dec(y); if y=0 then y:=n; 41 s:=s+jz[y,i-k+1]; 42 f[i]:=max(f[i],f[i-k]-spend[y]+s); 43 end; 44 end; 45 46 writeln(f[m]); 47 close(input); close(output); 48 end.