jzoj 模拟赛总结(2017.07.11)

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.

你可能感兴趣的:(暴力/枚举/模拟,高精度,树,动态规划)