2017.7.15 C组总结

来源:互联网 发布:码农网java入门 编辑:程序博客网 时间:2024/06/08 18:47

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;}
原创粉丝点击