• 2017.7.15 C组总结


    NO.1

    题目描述:有n首曲子,每一次播放值最大的音乐,每播完一首音乐,它的值平均分给其他n-1首曲子,如果不能平分,那么多出来的,顺次分给编号靠前的曲子

    思路:暴力模拟
    每次求出最大值,用两个变量记录它能平分的值和多出来的值
    然后循环,枚举1~n,
    ①如果l<>j就是不为本身,而且v>0还有剩的数
    那么,v–,a[j]=a[j]+w+1
    ②else a[j]+=w
    最后,将a[l]=0

    代码:

    var
      i,j,n,m,l,w,v:longint;
      a:array[0..1005] of longint;
    begin
      readln(n,m);
      for i:=1 to n do readln(a[i]);
      for i:=1 to m do
        begin
          l:=0;
          for j:=1 to n do if a[j]>a[l] then l:=j;
          writeln(l);
          w:=a[l] div (n-1);
          v:=a[l] mod (n-1);
          for j:=1 to n do
            begin
              if (j<>l) and (v>0) then
                begin
                  dec(v);
                  a[j]:=a[j]+w+1;
                end
              else inc(a[j],w);
            end;
          a[l]:=0;
        end;
    end.

    NO.2

    题目描述:有n次测量山的高度的值,(一座山定义为高度一开始单调上升(或者不变),然后单调下降(或者不变)),求最宽的山的宽度是多大

    思路:前缀和
    设l[i]为从i到左连续上升的长度,r[i]为从i到右连续上升的长度
    ①求l为if h[i]>=h[i-1] then l[i]:=l[i-1]+1,不然l[i]=1
    ②求l为if r[i]>=h[i+1] then r[i]:=r[i+1]+1,不然r[i]=1
    最后枚举i,求ans=max(ans,l[i]+r[i]-1)

    代码:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n,i,a[10001],d[10001],u[10001],ma;
    int main()
    {
        scanf("%d",&n);
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        for (i=1;i<=n;i++) if (a[i]>=a[i-1]) u[i]=u[i-1]+1; else u[i]=1;
        for (i=n;i>=1;i--) if (a[i]>=a[i+1]) d[i]=d[i+1]+1; else d[i]=1;
        for (i=1;i<=n;i++) ma=max(ma,u[i]+d[i]-1);
        printf("%d",ma);
    }

    NO.3

    题目描述:有n分钟,每一分钟可以选择跑d[i]米,耗1点疲劳值或休息一分钟,补一点疲劳值。疲劳值不能大于m,到最后疲劳值必须为0

    思路:dp
    设f[i][j]为第i分钟疲劳值为j能跑的最大距离
    状态转移方程为①当第i分钟跑时,f[i][j]=max(f[i][j],f[i-1][j-1]+d[i])
    ②因为她如果要休息就必须是疲劳值到0,
    那么就有一个前提,就是i>=j,那么f[i][0]=max(f[i][0],f[i-j][j])
    f[i][0]=max(f[i][0]+f[i-1][0]),改变答案

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n, m;
    int f[10010][510], v[10010];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&v[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                f[i][j]=max(f[i][j],f[i-1][j-1]+v[i]);
                if(i>=j) f[i][0]=max(f[i][0],f[i-j][j]);
            }
            f[i][0]=max(f[i][0],f[i-1][0]);
        }
        printf("%d", f[n][0]);
        return 0;
    }

    NO.4

    题目描述:求在一个矩阵中连接两个点,这两个点中间没有点挡住,两个点中间的距离必须为在[l1..l2]的区间中,求有多少种情况

    思路:数学+规律
    其实这题的本质就是要求矩阵的对角线
    首先,可以枚举从(0,0)出发,到任何一个点(i,j)的对角线
    那么如果要满足题目的情况,必须gcd(i,j)=0(因为对于任意两个点如果以它们作为左上角和右下角的矩阵的长和宽的最大公因数为1,那么这条对角线上只有两个点【左上角和右下角】),而且这条线的长度在[l1..l2]的区间内(可以用勾股定理)求出
    这个点对答案的贡献就是
    ①如果1<=i<=n,1<=j<=m,那么ans+=(n-i+1)*(m-i+1)*2(因为这个矩阵存在0坐标)
    ②如果1<=i<=m,1<=j<=n,那么ans+=(n-j+1)*(m-j+1)*2
    还要做一波特判,
    ①如果l1=1,那么就是连接两个相邻的点,ans+=(n+1)*m+(m+1)*n
    ②如果l1=1,l2>1,那么就是连接长宽为1的矩阵,ans+=n*m*2

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    unsigned long long ans;
    int n,m,l1,l2,maxn;
    bool gcd(int x,int y)
    {
         if (x==1) return true;
         if (y%x==0) return false;
         return gcd(y%x,x);
    }
    int sqr(int x){ return x*x; }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&l1,&l2);
        maxn=max(n,m);
        ans=0;
        for (int i=1;i<=maxn-1;i++)
            for (int j=i+1;j<=maxn;j++)
                if ((sqr(i)+sqr(j)>=sqr(l1))&&(sqr(i)+sqr(j)<=sqr(l2)))
                   if (gcd(i,j)) 
                   {
                        if (i<=n&&j<=m) ans+=(n-i+1)*(m-j+1)*2;
                        if (j<=n&&i<=m) ans+=(n-j+1)*(m-i+1)*2;
                   }
        if (l1==1) ans=ans+n*(m+1)+m*(n+1);
        if (l1==1&&l2>1) ans=ans+n*m*2;
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    vue_ajax-axios的使用
    laravel验证码扩展包gregwar/captcha的使用
    如何让你的网页变为黑白色
    laravle Str::random(num)函数
    laravel_日志查看-logViewer工具的使用
    如何自定义css的鼠标样式
    公鸡3块钱1只,母鸡5块钱1只,小鸡1块钱3只,用100块买100只鸡,一共多少种买法,分别是什么?
    假设某人有100000现金。 每经过一次路口需要进行一次交费。 交通规则为为当他现金大于50000时每次需要交5%如果现金小于等于50000时每次交5000。 请写一程序计算此人可以经过多少次这个路口
    本周总结
    本周总结
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412265.html
Copyright © 2020-2023  润新知