2017年12月励志杯月赛 题解

来源:互联网 发布:史书 知乎 编辑:程序博客网 时间:2024/06/15 17:01

T1 中位数(median.cpp)

【题目描述】
有一个长度为N的数列{A1,A2,…An},这N和数字恰好是1..N的一个排列。你需要统计有多少个子序列{Ai,Ai+1,…Aj}满足:i<=j且j-i+1为奇数,序列的中位数为B。例如{5,1,3}的中位数为3。
【输入文件】
第一行包含两个正整数N和B;第二行包含N个整数,第i个整数为Ai。
【输出文件】
仅包含一个整数,为满足条件的子序列的个数。
【样例输入】
7 4
5 7 2 4 3 1 6
【样例输出】
4
【数据规模】
对于30%的数据中,满足N<=100;
对于60%的数据中,满足N<=1000;
对于100%的数据中,满足N<=100000,1<=B<=N。

【题解】【规律+递推】
【因为B是序列的中位数,所以B一定存在于序列中,所以,记录B在序列中的位置num,并把相对应的数置为0;把小于B的数置为-1;大于B的数置为1。】
【分别从num向左向右扫描,并分别设一个累加器,将枚举时遇到的0、1、-1都加入累加器里,并分别用L、R数组记录累加器中每个数出现的次数】
【最后求:∑L[i]*R[-i](但因为C++没有负数下标,所以要整体向右移n个下标)】

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[100010],L[200010],R[200010],n,b,num,ans;int main(){    freopen("median.in","r",stdin);    freopen("median.out","w",stdout);    int i,j;    scanf("%d%d",&n,&b);    for(i=1;i<=n;++i)     {        scanf("%d",&a[i]);        if(a[i]==b) {num=i; a[i]=0; continue;}        if(a[i]>b) a[i]=1;         else a[i]=-1;     }    int l=n,r=n;    for(i=num;i>0;--i) l+=a[i],L[l]++;    for(i=num;i<=n;++i) r+=a[i],R[r]++;    int len=2*n;    for(i=0;i<=len;++i)      ans+=(L[i]*R[len-i]);    printf("%d\n",ans);    return 0;}

一、敲砖块
【题目描述】
在一个凹槽中放置了N层砖块,最上面的一层油N块砖,从上到下每层一次减少一块砖。每块砖都有一个分支,敲掉这块砖就能得到相应的分值,如图所示。

如果你想敲掉第i层的第j块砖的话,若i=1,你可以直接敲掉它;若i>1,则你必须先敲掉第i-1层的第j和第j+1块砖。
你现在可以敲掉最多M块砖,求得分最多能有多少。
【输入文件】
输入文件的第一行有两个正整数N和M;
接下来的N行,描述这N层砖块上的分值A[i,j],满足0<=A[i,j]<=100。
【输出文件】
仅一行,包含一个整数,为最大的得分。
【样例输入】
4 5
2 2 3 4
8 2 7
2 3
49
【样例输出】
19
【数据规模】
对于20%的数据,满足1<=N<=10,1<=M<=30
对于100%的数据,满足1<=N<=50,1<=M<=500。

题解:
首先我们将砖块向左对齐,变成一个直角三角形的形式,可以发现:
1. 每一列必须敲掉从第一行开始的从上到下的若干个砖块
2.如果某一列敲掉了K个砖块,那么其右边的那一列至少敲掉了K-1个砖块。
所以我们可以dp。
f [ i ] [ j ] [ k ] 表示从右到左已经敲到了第I列,其中第I列敲掉了J个砖块且还剩K个砖块所得到的最大价值。
f[i][j][k]=max(f[i+1][v][k+j])+a[1][i]+..+a[1]=j-1>j

#include<cstdio>#include<cstring>#include<iostream>using namespace std;int n,m,a[510][510],fi,fj,fk,v[510][510],f[60][60][510],ans; int main(){    freopen("brike.in","r",stdin);    freopen("brike.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)      for (int j=1;j<=n-i+1;j++)        {            scanf("%d",&a[i][j]);        }    for (int i=n;i>=1;i--)      for (int j=1;j<=n-i+1;j++)         v[i][j]=v[i][j-1]+a[j][i];    memset(f,-1,sizeof(f));    f[n+1][0][m]=0;    for (int j=n;j>=1;j--)      for (int i=0;i<=n-j+1;i++)        for (int k=m-i;k>=0;k--)        {            for (int l=i-1;l<=n-j+1;l++)            if (f[j+1][l][k+i]!=-1)                f[j][i][k]=max(f[j][i][k],f[j+1][l][k+i]+v[j][i]);            if (ans<f[j][i][k])            {                ans=f[j][i][k];            }        }      printf("%d",ans); }

T3 邮递员送信

【问题描述】
有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。
【样例输入】

5 102 3 51 5 53 5 61 2 81 3 85 3 44 1 84 5 33 5 65 4 2

【样例输出】

83

【题解 思路1】
题解:大水题,考试想到了两遍最短路,却没有继续向深层思考。只要将边反过来,那之前是1到2~n个点的最短路,反过来就是2~n个点到1的最短路,两遍dijkstra便可。同时要注意题目中有重边出现,用邻接矩阵注意判重,这也显示出了邻接表的优势,邻接表不需要判重。

#include<cmath>#include<cstdio>#include<iostream>#include<cstring>using namespace std;int n,m,maxx=1e9,minn,t,z,i,j,k,x,y;long long ans;bool flag[1006];int c[1006],d[1006];int f1[1006][1006],f2[1006][1006];int get(){    int x=0,p=1;    char c;    c=getchar();    while (c<'0'||c>'9') {if (c=='-') p=-1;c=getchar();}    while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}    return x*p;}int main(){       n=get();m=get();    memset(f1,127/3,sizeof(f1));    memset(f2,127/3,sizeof(f2));    memset(c,127/3,sizeof(c));    memset(d,127/3,sizeof(d));    maxx=f1[0][0];    for (i=1;i<=m;i++)    {        x=get();y=get();z=get();        if (f1[x][y]!=maxx) f1[x][y]=min(f1[x][y],z);        else f1[x][y]=z;        if (f2[y][x]!=maxx) f2[y][x]=min(f2[y][x],z);        else f2[y][x]=z;    }    memset(flag,false,sizeof(flag));    for (i=1;i<=n;i++) c[i]=f1[1][i];    flag[1]=true;    c[1]=0;    for (i=1;i<=n-1;i++)    {        minn=maxx;        k=0;        for (j=1;j<=n;j++)            if ((!flag[j])&&(c[j]<minn))            {                minn=c[j];                k=j;            }        if (k==0) break;        flag[k]=true;        for (j=1;j<=n;j++)        {            if (c[k]+f1[k][j]<c[j])                c[j]=c[k]+f1[k][j];        }    }    memset(flag,false,sizeof(flag));    for (i=1;i<=n;i++) d[i]=f2[1][i];    flag[1]=true;    d[1]=0;    for (i=1;i<=n-1;i++)    {        minn=maxx;        k=0;        for (j=1;j<=n;j++)            if ((!flag[j])&&(d[j]<minn))            {                minn=d[j];                k=j;            }        if (k==0) break;        flag[k]=true;        for (j=1;j<=n;j++)        {            if (d[k]+f2[k][j]<d[j])                d[j]=d[k]+f2[k][j];        }    }    for (i=1;i<=n;i++)        ans+=c[i]+d[i];     printf("%lld",ans);  }

【题解】【最短路】
【这道题思路十分精妙,因为是有向图,所以刚开始按数据建图,跑一遍SPFA;再把所有边反向,再跑一遍SPFA。把两次的最短路都加入答案】

#include<queue>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;int f[1010][1010];int a[100010],nxt[100010],p[1010],val[100010],tot;int n,m;ll ans,dis[1010];inline void add(int x,int y,int v){    tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot; val[tot]=v;}inline void spfa(){    queue<int>que;    memset(dis,127/3,sizeof(dis));    dis[1]=0; que.push(1);    while(!que.empty())     {        int u=que.front(); que.pop();        int v=p[u];        while(v!=-1)         {            if(dis[a[v]]>dis[u]+(ll)val[v])             {                dis[a[v]]=dis[u]+(ll)val[v];                que.push(a[v]);               }            v=nxt[v];          }     }    for(int i=2;i<=n;++i) ans+=dis[i];    return;}int main(){    freopen("post.in","r",stdin);    freopen("post.out","w",stdout);    int i,j;    memset(f,127,sizeof(f));    memset(p,-1,sizeof(p));    memset(nxt,-1,sizeof(nxt));    scanf("%d%d",&n,&m);    for(i=1;i<=m;++i)      {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        if(f[x][y]>z) f[x][y]=z;        add(x,y,z);      }    spfa(); tot=0;    memset(p,-1,sizeof(p));    memset(nxt,-1,sizeof(nxt));    for(i=1;i<=n;++i)     for(j=1;j<=n;++j)      if(i!=j&&f[i][j]!=f[0][0])       add(j,i,f[i][j]);    spfa();    printf("%lld\n",ans);    return 0;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 iphone6s声音小怎么办 平板电脑蓝屏怎么办 微信群聊有回音怎么办 手机内屏漏液怎么办 6s电越充越少怎么办 iphone6内屏漏液怎么办 iphone内屏漏液怎么办 苹果6充不进电怎么办 手机电越充越少怎么办 手机内屏有黑块怎么办 苹果肌太宽怎么办 苹果肌发达怎么办 苹果肌过大怎么办 电视液晶屏划痕怎么办 iphone翘屏怎么办 iphone黑屏转圈怎么办 iphone8plus失灵怎么办 苹果手机打不开白屏怎么办 苹果paid死机怎么办 苹果手机屏幕卡住怎么办 ipad屏幕失灵怎么办 手机触屏太灵敏怎么办 华硕触摸屏失灵怎么办 ipad换屏后乱跳怎么办 手机屏幕突然失灵怎么办 按键不灵敏了怎么办 小米死机了怎么办 小米手机屏幕不灵敏怎么办 iphone5滑动失灵怎么办 电脑滑动失灵怎么办 sim卡槽坏了怎么办 手机进水后跳屏怎么办 手机屏幕烧坏了怎么办 华为手机屏幕不灵敏怎么办 手机屏幕有残影怎么办 su卡怎么办 su卡顿怎么办 苹果8玩吃鸡卡怎么办 玩吃鸡手机卡顿怎么办 玩手机游戏卡怎么办 苹果停用怎么办