JZOJ2017.07.11 C组

题目描述

Oliver进入初中后,觉得自己不能总是玩儿了,应该要好好学习了。正好一次考试结束了,Oliver想知道自己的语文,数学,英语分别与语文年级第一,数学年级第一,英语年级第一相差多少。
由于Oliver所在年级有N个人,所以Oliver想你编个程序帮帮他。

思路:

排序,没什么好说

代码:

type arr=array[0..31] of longint;
var n:int64;
    i:longint;
    a,b,c,m1,m2,m3,x,y,z:string;

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;

function max(x,y:string):string;
begin
  //if x>y then exit(x) else exit(y);
  if length(x)=length(y) then
  begin
    if x>y then exit(x) else exit(y);
  end else
  if length(x)>length(y) then exit(x) else exit(y);
end;
begin
  assign(input,'score.in');
  assign(output,'score.out');
  reset(input);
  rewrite(output);
  readln(a);
  readln(b);
  readln(c);
  m1:=a; m2:=b; m3:=c;
  readln(n);
  for i:=1 to n do
  begin
    //read(x,y,z);
    readln(x);
    readln(y);
    readln(z);
    m1:=max(x,m1); m2:=max(y,m2); m3:=max(z,m3);
  end;
  write(jian(m1,a),' ',jian(m2,b),' ',jian(m3,c));
  close(input);
  close(output);
end.

T2

题目描述:

玩过Diablo的人对技能树一定是很熟悉的。一颗技能树的每个结点都是一项技能,要学会这项技能则需要耗费一定的技能点数。只有学会了某一项技能以后,才能继续学习它的后继技能。每项技能又有着不同的级别,级别越高效果越好,而技能的升级也是需要 耗费技能点数的。
有个玩家积攒了一定的技能点数,他想尽可能地利用这些技能点数来达到最好的效果。因此他给所有的级别都打上了分,他认为效果越好的分数也越高。现在他要你帮忙寻找一个分配技能点数的方案,使得分数总和最高。

思路:

树形DP
设l1[i][j]表示为第i个技能j级的位置(即输入顺序) 
设a[i][0]表示技能i的前继技能和上一级的个数 
a[i][j]表示技能i的第j级的前继技能和上一级的位置 
要求出对于任何一个结点的后继结点和前继结点、相应的技能点(f[i])和分数(w[i]) 
然后,对于i的父亲名字==j的名字(就是j是i的前继技能),那么a[l1[j][1]][0]++,a[l1[++y,1],a[l1[y,1],0]]=l1[i,1](就是求出对于i结点的前继技能) 
于是要造一棵树,表示对于每个结点的要学的两个端点(也就是说对于i结点要学的技能就在[l..r]这个区间内) 
设dp[i][j]表示为从i出发,用了j技能点的最大分数值,那么状态转移方程就是dp[x][i]=max(dp[r[x]][i],dp[l[x]][j]+dp[r[x]][i-j-f[x]]+w[x]) 
0<=i<=p,1<=j<=i-f[x]

代码:

uses math;
var n,m,x,y,s,root,p:longint;
    l1:array[0..20,0..20] of longint;
    l,r,f,w:array[0..400]of longint;
    a:array[0..400,0..400]of longint;
    dp:array[-1..400,0..100]of longint;
    name,fname:array[0..20]of string;
procedure build(t:longint);
var i:longint;
begin
  for i:=1 to a[t,0]-1 do r[a[t,i]]:=a[t,i+1];
  if a[t,0]>0 then l[t]:=a[t,1];
  for i:=1 to a[t,0] do build(a[t,i]);
end;
procedure init;
var i,j:longint;
begin
  assign(input,'skill.in');
  assign(output,'skill.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do
  begin
    readln(name[i]);
    readln(fname[i]);
    readln(s);
    for j:=1 to s do
    begin
      inc(x);
      l1[i,j]:=x;
      read(y);
      f[x]:=y;
      if j>1 then
      begin
        inc(a[l1[i,j-1],0]);
        a[l1[i,j-1],a[l1[i,j-1],0]]:=l1[i,j];
      end;
    end;
    readln;
    for j:=1 to s do
    begin
      read(y);
      w[l1[i,j]]:=y;
    end;
    readln;
  end;
  for i:=1 to n do
  begin
    y:=root;
    for j:=1 to n do
      if (fname[i]=name[j]) then
      begin
        y:=j;
        break;
      end;
    inc(a[l1[y,1],0]);
    a[l1[++y,1],a[l1[y,1],0]]:=l1[i,1];
  end;
  readln(p);
  for i:=1 to n do
  begin
    read(y);
    for j:=1 to y do
    begin
      w[l1[i][j]]:=0;
      f[l1[i][j]]:=0;
    end;
  end;
  for i:=0 to x do
  begin
    l[i]:=-1;
    r[i]:=-1;
  end;
  build(root);
end;
procedure tdp(x:longint);
var i,j:longint;
begin
  if x<0 then exit;
  tdp(l[x]);
  tdp(r[x]);
  for i:=0 to p do
  begin
    dp[x,i]:=dp[r[x],i];
    for j:=0 to i-f[x] do
      dp[x,i]:=max(dp[x,i],dp[l[x],j]+dp[r[x],i-j-f[x]]+w[x]);
  end;
end;
begin
  init;
  tdp(root);
  writeln(dp[root,p]);
  close(input);
  close(output);
end.

T3

题目描述:

DaA 和他的朋友组成一个团队去旅行了。他们每个人都准备了一个背包,用来装旅行用的物品。他们的背包有两个特点:
1. 每个人的背包能装无限多的物品,每种物品有一个价值,但只能装一件;
2. 每个人都很有个性,所以每个人的背包不会完全相同。
DaA 的团队中有M 个人,那么对于整个团队,背包价值和最大是多少呢?

思路:

贪心+递推 
因为每件物品在每个背包只能装一个,那么设f[i]来表示分数值为i的情况有多少种 
递推式就是f[i]=f[i-w[i]]+f[i] 
然后downto,用贪心得出最大可能性ans,这里的贪心有两种操作: 
①如果f[i]<=m 
ans=ans+i*f[i]; 
m=m-f[i] 
②如果f[i]>m 
ans=ans+i*m 
break

代码:

uses math;
var n,m,x,y,s,root,p:longint;
    l1:array[0..20,0..20] of longint;
    l,r,f,w:array[0..400]of longint;
    a:array[0..400,0..400]of longint;
    dp:array[-1..400,0..100]of longint;
    name,fname:array[0..20]of string;
procedure build(t:longint);
var i:longint;
begin
  for i:=1 to a[t,0]-1 do r[a[t,i]]:=a[t,i+1];
  if a[t,0]>0 then l[t]:=a[t,1];
  for i:=1 to a[t,0] do build(a[t,i]);
end;
procedure init;
var i,j:longint;
begin
  assign(input,'skill.in');
  assign(output,'skill.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do
  begin
    readln(name[i]);
    readln(fname[i]);
    readln(s);
    for j:=1 to s do
    begin
      inc(x);
      l1[i,j]:=x;
      read(y);
      f[x]:=y;
      if j>1 then
      begin
        inc(a[l1[i,j-1],0]);
        a[l1[i,j-1],a[l1[i,j-1],0]]:=l1[i,j];
      end;
    end;
    readln;
    for j:=1 to s do
    begin
      read(y);
      w[l1[i,j]]:=y;
    end;
    readln;
  end;
  for i:=1 to n do
  begin
    y:=root;
    for j:=1 to n do
      if (fname[i]=name[j]) then
      begin
        y:=j;
        break;
      end;
    inc(a[l1[y,1],0]);
    a[l1[++y,1],a[l1[y,1],0]]:=l1[i,1];
  end;
  readln(p);
  for i:=1 to n do
  begin
    read(y);
    for j:=1 to y do
    begin
      w[l1[i][j]]:=0;
      f[l1[i][j]]:=0;
    end;
  end;
  for i:=0 to x do
  begin
    l[i]:=-1;
    r[i]:=-1;
  end;
  build(root);
end;
procedure tdp(x:longint);
var i,j:longint;
begin
  if x<0 then exit;
  tdp(l[x]);
  tdp(r[x]);
  for i:=0 to p do
  begin
    dp[x,i]:=dp[r[x],i];
    for j:=0 to i-f[x] do
      dp[x,i]:=max(dp[x,i],dp[l[x],j]+dp[r[x],i-j-f[x]]+w[x]);
  end;
end;
begin
  init;
  tdp(root);
  writeln(dp[root,p]);
  close(input);
  close(output);
end.

T4

题目描述:

从前有一条神奇的项链,为什么说它神奇呢?因为它有两个性质:
1. 神奇的项链可以拉成一条线,线上依次是N 个珠子,每个珠子有一个能量值Ei;
2. 除了第一个和最后一个珠子,其他珠子都满足Ei=(Ei-1+Ei+1)/2+Di。
由于这条项链很长,我们只能知道其两端珠子的能量值。并且我们知道每个珠子的Di是多少。请聪明的你求出这N 个珠子的能量值分别是多少。

代码:

var a,b,c,s:array[0..500000] of int64;
    i,j,n,m:longint;
begin
  assign(input,'fett.in');
  assign(output,'fett.out');
  reset(input);
  rewrite(output);
  read(n,a[1],a[n]); write(a[1],' ');
  for i:=2 to n-1 do read(c[i]);
  s[2]:=1; b[1]:=a[1];
  for i:=3 to n do
  begin
    s[i]:=s[i-1]*2-s[i-2];
    b[i]:=2*b[i-1]-b[i-2]-2*c[i-1];
  end;
  a[2]:=(a[n]-b[n]) div s[n];
  write(a[2],' ');
  for i:=3 to n do
  begin
    a[i]:=2*a[i-1]-a[i-2]-2*c[i-1];
    write(a[i],' ');
  end;
  close(input);
  close(output);
end.

你可能感兴趣的:(题解,jzoj)