zoukankan      html  css  js  c++  java
  • 2017.7.11 C组总结

    NO.1

    题目描述:知道n+1(包括Oliver)个人的语文、数学、英语成绩,求出Oliver的数学、语文、英语分别和最高的分数差多少?

    思路:高精+排序
    考试一瞟数据最长的成绩<30位,便无奈至极,于是手动码起了高精
    因为他只用求出与最大的分差,所以可以用排序,将三科的最大成绩求出来
    再做三次高精减就可以A
    时间复杂度O(3*30+3nlogn)

    代码:

    uses math;
    const maxn=30;
    type arr=array[0..10001]of string;
    var x1,y1,z1:string;
        x,y,z:array[0..10001]of string;
        n,i:longint;
    
    procedure qsort(var x:arr;l,r:longint);
    var i,j:longint;
        mid:string;
    begin
      if l>=r then exit;
      i:=l; j:=r; mid:=x[(l+r) div 2];
      repeat
        while (length(x[i])=length(mid))and(x[i]>mid)or(length(x[i])>length(mid)) do inc(i);
        while (length(x[j])=length(mid))and(x[j]<mid)or(length(x[j])<length(mid)) do dec(j);
        if i<=j then
          begin
            x[0]:=x[i];
            x[i]:=x[j];
            x[j]:=x[0];
            inc(i);
            dec(j);
          end;
      until i>j;
      qsort(x,l,j);
      qsort(x,i,r);
    end;
    
    procedure jian(x,y:string);
    var i,g,l:longint;
        l1,l2,l3:array[0..30]of longint;
    begin
      fillchar(l1,sizeof(l1),#0);
      fillchar(l2,sizeof(l2),#0);
      fillchar(l3,sizeof(l3),#0);
      for i:=1 to length(x) do l1[maxn-length(x)+i]:=ord(x[i])-48;
      for i:=1 to length(y) do l2[maxn-length(y)+i]:=ord(y[i])-48;
      for i:=maxn downto 1 do
        begin
          g:=l1[i];
          if g<l2[i] then
            begin
              l1[i-1]:=l1[i-1]-1;
              g:=g+10;
            end;
          g:=g-l2[i];
          l3[i]:=g mod 10;
        end;
      l:=1;
      while (l3[l]=0)and(l<=maxn) do inc(l);
      for i:=l to maxn do write(l3[i]);
      write(' ');
    end;
    
    begin
      assign(input,'score.in');
      assign(output,'score.out');
      reset(input);
      rewrite(output);
      readln(x1);
      readln(y1);
      readln(z1);
      readln(n);
      for i:=1 to n do
        begin
          readln(x[i]);
          readln(y[i]);
          readln(z[i]);
        end;
      qsort(x,1,n);if (length(x1)=length(x[1]))and(x1>=x[1])or(length(x1)>length(x[1])) then write('0 ')
      else jian(x[1],x1);
      qsort(y,1,n);if (length(y1)=length(y[1]))and(y1>=y[1])or(length(y1)>length(y[1])) then write('0 ')
      else jian(y[1],y1);
      qsort(z,1,n);if (length(z1)=length(z[1]))and(z1>=z[1])or(length(z1)>length(z[1])) then write('0 ')
      else jian(z[1],z1);
      close(input);
      close(output);
    end.

    NO.2

    题目描述:有一棵技能树,每个节点都是一个技能,学习一个技能,才能学会它的后继技能,每项技能都有不同的等级,不同的等级耗不同的技能点,和拥有不同的分数。要求出最大的分数

    思路:树形DP+模拟
    乍一看,1<=n<=20,便想到搜索,旁边的黄大佬便码起了搜索,结果只有20!!!
    听了dalao的讲解,
    首先,设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,i,j: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(x:longint);
    var i:longint;
    begin
      for i:=1 to a[x,0]-1 do r[a[x,i]]:=a[x,i+1];
      if (a[x,0]>0) then l[x]:=a[x,1];
      for i:=1 to a[x,0] do build(a[x,i]);
    end;
    
    procedure treedp(x:longint);
    var i:longint;
    begin
      if x=-1 then exit;
      treedp(l[x]);
      treedp(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
      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);
      treedp(root);
      writeln(dp[root,p]);
      close(input);
      close(output);
    end.

    NO.3

    题目描述:用m个人n个物品,每个人的背包是无限大的,但是每件物品在每个背包只能装一个,而且每个背包都不完全相同,问最大的物品价值和是多少

    思路:贪心+递推
    因为每件物品在每个背包只能装一个,那么设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

    代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    unsigned long long ans,sum=0,f[25100];
    long n,m,w[510];
    int main()
    {
        freopen("team.in","r",stdin);
        freopen("team.out","w",stdout);
        scanf("%d%d",&m,&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
            sum=sum+w[i];
        }
        f[0]=1;
        for (int i=1;i<=n;i++)
        {
            for (int j=sum;j>=0;j--) if (j>=w[i]) f[j]+=f[j-w[i]];
        }
        ans=0;
        for (int i=sum;i>=0;i--)
            if (f[i]<=m)
            {
                m-=f[i];
                ans=ans+f[i]*i;
            }
            else
            {
                ans=ans+i*m;
                break;
            }
        printf("%lld",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    NO.4

    题目描述:有一串珠子,每个珠子有一个能量值E[i],除了前后两个珠子,其他的都符合Ei=(Ei-1+Ei+1)/2+Di,现在知道全部Di、E1和En,让你求出E2~E(n-1)

    思路:数学
    知道:2E2-E1-E3=2D2 ①
    2E3-E2-E4=2D3 ②
    2E4-E3-E5=2D4 ③
    ……
    然后,②*2-① 3E3-2E4=E1+2D2+4D3
    ③*3-② 4E4-3E5=E1+2D2+4D3+6D4
    ……
    可以得到规律k*Ek-(k-1)*Ek+1=E1+2D2+4D3+…+(k-1)*2*Dk
    把n-1当k代入得(N-1)*EN-1-(N-2)*EN=E1+2D2+4D3+…+(N-2)*2*DN-1
    然后就可以发现这个式子里只有一个未知数,直接求就好了

    代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    long long n,e[500000],a[500000],d[500000];
    int main()
    {
        freopen("fett.in","r",stdin);
        freopen("fett.out","w",stdout);
        scanf("%lld%lld",&n,&e[1]);
        scanf("%lld",&e[n]);
        for (int i=2;i<=n-1;i++) scanf("%lld",&d[i]);
        a[2]=0;
        a[3]=(a[2]-d[2])*2-e[1];
        for (int i=4;i<=n;i++) a[i]=(a[i-1]-d[i-1])*2-a[i-2];
        e[2]=(e[n]-a[n])/(n-1);
        for (int i=3;i<=n;i++) e[i]=(e[i-1]-d[i-1])*2-e[i-2];
        for (int i=1;i<=n;i++) printf("%lld ",e[i]);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    这次比赛,100(高精)+0+100(递推+贪心)+100(手动推公式)=300(第一)
    这次,考得还算可以,明天继续保持(∩_∩)

  • 相关阅读:
    sublime manjaro
    codeforce 1027C 贪心算法
    codeforce B
    java生成随机数保留数点后两位
    form表单无限提交的问题
    Jquery TimePicker时间箭头无法加载的问题(http://localhost:8080/css/images/ui-icons_444444_256x240.png)
    Mysql 创建事件时出现near‘DO create event...’错误
    线程之实现
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getResource(Pool.java:53)
    Recursion递归
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412270.html
Copyright © 2011-2022 走看看