T1.
Oliver的成绩:
题目大意:
一次考试结束了,Oliver给出自己的语文,数学,英语成绩(位数为M)分别与年级N个人中的语文年级第一,数学年级第一,英语年级第一相差多少,如果Oliver是第一,则输出0。
对于50%的数据,0 < N < 1000, 0 < M < 19.
对于100%的数据,0 < N < 10000, 0 < M < 30.且都为整数
题解:
看题不用想,字符串读入,然后判断长短,相同就按字典序比较,然后高精度随便搞搞。
O(3N)
var
o,maxa,maxb,maxc,a,b,c,a1,b1,c1:string;
i,j,n,m:longint;
function jian(kk,k:string):string;
var
aa,bb,cc:array [0..32] of longint;
i,j,la,lb,lc:longint;
begin
if length(kk)then exit('0');
if (length(kk)=length(k)) and (kk<=k) then exit('0');
fillchar(aa,sizeof(aa),0);
fillchar(bb,sizeof(bb),0);
fillchar(cc,sizeof(cc),0);
la:=length(kk);
lb:=length(k);
for i:=1 to la do aa[i]:=ord(kk[la-i+1])-48;
for i:=1 to lb do bb[i]:=ord(K[lb-i+1])-48;
i:=1;
while i<=la do
begin
if aa[i]then begin
aa[i]:=aa[i]+10;
aa[i+1]:=aa[i+1]-1;
end;
cc[i]:=aa[i]-bb[i];
inc(i);
end;
while cc[i]=0 do dec(i);
jian:='';
for j:=i downto 1 do
jian:=jian+chr(cc[j]+48);
end;
begin
assign(input,'score.in'); reset(input);
assign(output,'score.out'); rewrite(output);
readln(a);
readln(b);
readln(c);
readln(n);
for i:=1 to n do
begin
readln(a1);
readln(b1);
readln(c1);
o:=jian(a1,a);
if (length(o)>length(maxa)) or
((length(o)=length(maxa)) and (o>maxa))
then maxa:=o;
o:=jian(b1,b);
if (length(o)>length(maxb)) or
((length(o)=length(maxb)) and (o>maxb))
then maxb:=o;
o:=jian(c1,c);
if (length(o)>length(maxc)) or
((length(o)=length(maxc)) and (o>maxc))
then maxc:=o;
end;
writeln(maxa,' ',maxb,' ',maxc);
close(input); close(output);
end.
T2.
技能树:
题目大意:
一颗技能树上的每个结点都是一个技能,只有学会了某一项技能以后,才能继续学习它的后继技能。给出n种技能,以及每个技能的前提要求技能,空则表示该技能不需要前提,还有一个L表示技能的最高等级,给出1~L个技能点需求,表示i-1级升到第i级所需要的技能点数(0级表示没有学习过),还有1~L个增幅效果,表示从第I-1级升级到第I级的效果评分。最后给出角色当前习得的技能级别,求分配P技能点数的方案,使得分数总和最高。数据保证不出现非法情况。
1<=n<=20
1<=L<=20
技能点数P<=20
题解:
树形DP+模拟:
等我随便搞搞,很快A,相信我
T3.
团队背包:
题目大意:
M个人都准备了一个背包,用来装旅行用的物品,有N个物品,价值为wi
他们的背包有两个特点:
1. 每个人的背包能装无限多的物品,每种物品有一个价值,但只能装一件;
2. 每个人都很有个性,所以每个人的背包不会完全相同。
求背包价值和最大是多少呢?
【数据规模】
30%的数据 1<=M,N<=15。
60%的数据 1<=M<=200,1<=N<=100。
100%的数据 1<=M<=1,000,000,1<=N<=500,0 < wi<=50。
输出请注意使用64 位整数(Pascal 中的Int64,C++中的long long)。
题解:
DP:
f[i,j]表示前i个物品装j价值物品的方案总数。
然后推出状态转移方程:
f[i,j]:=f[i-1,a[i]]+f[i-1,j-a[i]]
然后如果觉得内存不够优美可以学我滚动滚动,不过第二重循环必须要注意倒推!!
然后从大到小枚举j价值的物品的方案是否出现,出现就用掉,知道用的M个背包都没了。
时间复杂度:O(NΣw[i])
var
f:Array [0..25001] of int64;
a:array [0..501] of longint;
i,j,n,m,x,sum:longint;
ans:int64;
begin
assign(input,'team.in'); reset(input);
assign(output,'team.out');rewrite(output);
readln(m,n);
for i:=1 to n do
begin
read(a[i]);
sum:=sum+a[i];
end;
f[0]:=1;
for i:=1 to n do
begin
for j:=sum downto 0 do
if j>=a[i] then f[j]:=f[j]+f[j-a[i]];
end;
for i:=sum downto 0 do
if m>=f[i]
then begin
m:=m-f[i];
ans:=ans+f[i]*i;
end
else begin
ans:=ans+m*i;
break;
end;
writeln(ans);
close(input); close(output);
end.
T4.
神奇的项链:
从前有一条神奇的项链,为什么说它神奇呢?因为它有两个性质:
1. 神奇的项链可以拉成一条线,线上依次是N 个珠子,每个珠子有一个能量值Ei;
2. 除了第一个和最后一个珠子,其他珠子都满足Ei=(Ei-1+Ei+1)/2+Di。
由于这条项链很长,我们只能知道其两端珠子e[1],e[n]的能量值。并且我们知道每个珠子的Di是多少。请聪明的你求出这N 个珠子的能量值分别是多少。
任意珠子满足(Ei-1+Ei+1) Mod 2=0
40%的数据 1 < N<=100。
70%的数据 1 < N<=5,000,所有数据(包括计算中的)不超过10^9。
100%的数据 1 < N<=500,000,|E1|、|EN|<=10^14,|Di|<=10^4。
题解:
时间复杂度很明显是O(N)做法,然后看数据要开Int64 / long long
根据e[i]=e[i-1]+e[i+1]/2 +d[i]
我们可以推理
e[i]=e[i-1]/2+e[i+1]/2+d[i]
2e[i]=e[i-1]+e[i+1]+2d[i]
e[i+1]=2e[i]-e[i-1]-2d[i]
然后因为任意位置皆满足此公式,SO
i前移
e[i]=2e[i-1]-e[i-2]-2d[i-1]
因为i-1,i-2的关系,所以要保证i>=3,所以我们先假设e[2]=x
然后推出后面的关系
怎么假设未知数呢?
相信很多人不明白,我一开始也挺困惑,不过,我发现!
设e[i]=sum[i]*X+p[i]
p[i]表示从前面推到第i个珠子能累加到的无未知数X的整数值。
sum[i]表示从前面推到第i个珠子有多少个X,即当前X的系数。
然后最后推到e[N]
就可以发现
e[2]=X=(e[N]-p[n])/sum[n]
然后推一遍
时间复杂度:O(N)
var
sum,e,p,d:Array [0..500001] of int64;
i,j,n,m:longint;
begin
assign(input,'fett.in'); reset(input);
assign(output,'fett.out'); rewrite(output);
read(n); read(e[1],e[n]); readln;
for i:=2 to n-1 do read(d[i]); readln;
sum[2]:=1; p[1]:=e[1]; p[2]:=0;
for i:=3 to n do
begin
sum[i]:=sum[i-1]*2-sum[i-2];
p[i]:=-p[i-2]+2*p[i-1]-2*d[i-1];
end;
write(e[1]);
e[2]:=(e[n]-p[n]) div sum[n];
write(' ',e[2]);
for i:=3 to n do
begin
e[i]:=2*e[i-1]-e[i-2]-2*d[i-1];
write(' ',e[i]);
end;
close(input); close(output);
end.