noip普及组复赛模拟试题14(附答案)

noip普及组复赛模拟试题14(附答案)
noip普及组复赛模拟试题14(附答案)

解的个数(count)

给定一个正整数K,问有多少和正整数X,Y满足X>=Y且1/K=1/X+1/Y,将所有解按X降序输出。

输入

第一行一个数T,表示数据组数

以下T行,每行一个数K

输出

T部分,每部分第一行一个数K,以下一次按X降序输出所有解,个数见样例,注意=+两边都有空格。

样例输入

2

2

12

样例输出

2

1/2 = 1/6 + 1/3

1/2 = 1/4 + 1/4

8

1/12 = 1/156 + 1/13

1/12 = 1/84 + 1/14

1/12 = 1/60 + 1/15

1/12 = 1/48 + 1/16

1/12 = 1/36 + 1/18

1/12 = 1/30 + 1/20

1/12 = 1/28 + 1/21

1/12 = 1/24 + 1/24

数据规模

30% K<=20

100% K<=10000,T<=10

标程:

var t,i,j,l,n,k:integer;

a:array[1..20] of integer;

b,c:array[1..10000] of longint;

procedure shou(n:integer);

var k,s:longint;

begin

k:=n+1;s:=n*2;l:=0;

for i:=k to s do

begin

if n*i mod (i-n)=0 then

begin

inc(l);

b[l]:=(n*i) div (i-n);c[l]:=i;

end;

end;

end;

begin

assign(input,'count.in');

reset(input);

assign(output,'count.out'); rewrite(output);

readln(t);

for i:=1 to t do

readln(a[i]);

for k:=1 to t do

begin

shou(a[k]);

writeln(l);

for j:=1 to l do

writeln(1,'/',a[k],' ','=',' ',1,'/',b[j],' ','+',' ',1,'/',c[j]);

end;

close(input);

close(output);

end.

输入

3

4

15

32

输出

3

1/4 = 1/20 + 1/5

1/4 = 1/12 + 1/6

1/4 = 1/8 + 1/8

5

1/15 = 1/240 + 1/16

1/15 = 1/90 + 1/18

1/15 = 1/60 + 1/20

1/15 = 1/40 + 1/24

1/15 = 1/30 + 1/30

6

1/32 = 1/1056 + 1/33

1/32 = 1/544 + 1/34

1/32 = 1/288 + 1/36

1/32 = 1/160 + 1/40

1/32 = 1/96 + 1/48

1/32 = 1/64 + 1/64

不等数列(num.cpp/c/pas)【题目描述】将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个。答案对2012取模。

【输入格式】

第一行2个整数n,k。

【输出格式】

一个整数表示答案。

【样例输入】

5 2

【样例输出】

66

【数据范围】

对于30%的数据:n <= 10

对于100%的数据:k < n <= 1000,

题解:

对于30% n<=10的数据,搜索打表,状态压缩动态规划......

对于1--n等类似的排列计数问题,以动态规划和组合数学2种大方向为基本解决方向。

组合数学在noip最难也就到杨辉三角左右,所以这题我从动态规划展开。

如果此类排列问题在脑中的模型是:“有n个格子,填入1--n”,那么相对应的DP就不得不记录哪些数填过了(从左到右填入)或者哪些格子填过了(从小到大填入)。这样一来就必须要使用状态压缩来存储这些信息,就使得复杂度变得难以接受。

而如果换个模型:“从小到大把数字插入数列”。注意是数列而不是格子,这样一来就不需要记录是哪些数字插入了(而只要记录插入到了第几个数字),同时不需要记录每个数字的具体位置,也不需要记录数字的相对位置,而只需记录相对关系的数目(对本题而言就是有几个“<”)。

因为是从小到大插入数字,所以当前插入的数字一定大于所有已经插入的。

蓝色是当前插入的数字,如果它插入到<关系的2个数字之间(或者数列最左端),就会使数列的<数量不变,>数量+1:

类似的,插入到>关系的2个数字之间(或者数列最右端),数列的<数量+1,>数量不变。

F[i][j]表示前i个数字构成的数列中,恰有j个‘<’号的方案数(‘>’号就有i-j-1个)。

F[i][j]=F[i-1][j-1]*(i-j)+F[i-1][j]*(j+1).

时空复杂度:O(n^2)

若打表则时间复杂度为O(1)

【参考程序】

var n,k,i,j:integer;

f:array[0..10001,0..1001] of longint;

begin

assign(input,'num.in');

reset(input);

assign(output,'num.out');

rewrite(output);

readln(n,k);

for i:=1 to n do

begin

f[i,0]:=1;

f[i,i-1]:=1;

end;

for i:=1 to n do

for j:=1 to k do

begin

if j>=i-1 then continue;

f[i,j]:=(f[i-1,j-1]*(i-j)+f[i-1,j]*(j+1)) mod 2012;

end;

writeln(f[n,k] mod 2012);

close(input);

close(output);

end.

输入9 4 输出1266

输入300 12 输出700

输入1000 126 输出612

商店老板给Ezio拿出了n件装备,每个装备有一个标号a,这n件装备排成一排,他要求Ezio从中剔除一些装备,使得剩下的装备在顺序不变的情况下成为一套,装备成为一套的条件是,每相邻的两件装备标号不互质。他说如果Ezio能找出剩下装备最多的一套装备,他就把这套装备送给Ezio。聪明的Ezio当然能够搞定。不过他想知道最多能剩下多少装备。

输入input

第一行一个数n

第二行n个数,表示每件装备的标号a,每两个数之间用一个空格隔开,结尾无空格

输出output

一个整数,表示最多能剩下的装备数

样例输入sample input

6

6 2 3 15 4 5

样例输出sample output

4

(只需删掉原序列中的2和4,即余下的序列为6 3 15 5,每相邻两个不互质,故最多剩下4件。)

数据范围

对于30%数据n<=1000

对于100%数据n<=100000 a<=10000

思路:把a[i]分解质因数,用b数组记录前i-1个数中包含某个因子能组成的最

长的序列的长度。a[i]的k个因子s[1]到s[k] 找出

max(b[s[j]])然后把b[s[1]]到b[s[k]]都赋值为max+1。最后找出max(b[i])

程序:

var

a:array[1..100000]of longint;

b,s:array[1..10000]of longint;

n,m,i,j,k,ans,max:longint;

procedure init;

begin

readln(n);

for i:=1 to n do read(a[i]);

fillchar(b,sizeof(b),0);

end;

procedure fj(x:longint);

var

i,j:longint;

begin

max:=0;

k:=0; i:=1;

repeat

inc(i);

if x mod i=0 then

begin

inc(k);

s[k]:=i;

if max

end;

while x mod i=0 do x:=x div i;

until x=1;

for j:=1 to k do

b[s[j]]:=max+1;

end;

procedure doit;

begin

for i:=1 to n do fj(a[i]);

ans:=0;

for i:=1 to 10000 do

if ans

writeln(ans);

end;

begin

assign(input,'arm.in');

assign(output,'arm.out');

reset(input);

rewrite(output);

init;

doit;

close(input);

close(output);

end.

输入10

6 9 2 3 12 15 4 8 5 16 输出7

输入34

126 765 3212 5655 2316 978 856 432 1248 2568 6688 8874 9025 5530 248 512 395 648 9010 2450 933 420 736 95 66 120 45 24 90 55 1280 3456 234 542 输出29

【问题描述】

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

为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边的路灯,而事实并非如此,因为在关的过程中适当地调头有可能会更省一些。

现在已知老张走的速度为1m/s,每个路灯的位置(是一个整数,即距路线起点的距离,单位:m)、功率(W),老张关灯所用的时间很短而可以忽略不计。请你为老张编一程序来安排关灯的顺序,使从老张开始关灯时刻算起所有灯消耗电最少(灯关掉后便不再消耗电了)。

【输入】

文件第一行是两个数字n(0

接下来n行,每行两个数据,表示第1盏到第n盏路灯的位置和功率。

【输出】

一个数据,即最少的功耗(单位:J,1J=1W·s)。

【样例】

power.in power.out

5 3 270 {此时关灯顺序为3 4 2 1 5,不必输出这个关灯顺序}

2 10

3 20

5 20

6 30

8 10

【参考程序】

const

fi='powers.in';

fo='powers.out';

var

N,C:integer;

mem:array[1..50,0..1]of integer;

tot,ans:longint;

PROCEDURE Init;

var

i:integer;

begin

{assign(input,fi);

reset(input);}

readln(N,C);

tot:=0;

for i:=1 to N do

begin

readln(mem[i,0],mem[i,1]);

tot:=tot+mem[i,1];

end;

tot:=tot-mem[C,1];

close(input);

ans:=maxlongint;

end;

PROCEDURE Kernel(l,r,now:byte;jps,sum:longint);

begin

if sum>ans then

exit;

if (l=0)and(r=N+1) then

begin

if sum

ans:=sum;

exit;

end;

if l>=1 then

Kernel(l-1,r,l,jps-mem[l,1],sum+jps*(mem[now,0]-mem[l,0])); if r<=N then

Kernel(l,r+1,r,jps-mem[r,1],sum+jps*(mem[r,0]-mem[now,0])); end;

PROCEDURE Print;

begin

{assign(output,fo);

rewrite(output); }

writeln(ans);

close(output);

end;

begin

Init;

if N=1 then

begin

ans:=0;

Print;

halt;

end;

Kernel(C-1,C+1,C,tot,0); Print;

end.

输入

10 4

2 20

3 25

5 30

7 20

8 40

10 35

12 32

13 26

15 24

18 36 输出2959

输入20 7

2 35

4 26

5 28

6 18

9 20

10 24

12 25

14 38

15 40

16 29

18 37

19 26

20 33

21 45

23 41

24 36

25 48

27 39

30 26

31 43 输出11470

相关文档
最新文档