CF 812 ABC

来源:互联网 发布:咬人猫年龄 知乎 编辑:程序博客网 时间:2024/06/11 17:06

哭诉:

和省赛队友在宿舍的自习室打的。本来过了A。B莫名的被卡,当时没注意C,打完发现C居然是最好做的.比赛快结束的时候A题又被Hack,于是0题滚粗。QaQ!

A题:http://codeforces.com/contest/812/problem/A

题意:一个十字路口,请你判断是否会出现相撞的情况,个人感觉是道卡题意的题。

思路:考虑四条路有没有行人,如果有那么这条路上车不能走,它的上一个路口不能右拐,下一个路口不能左拐,对面的路口不能直行!

#include <iostream>#include<algorithm>#include<stdio.h>#include<string.h>#include<queue>int a[4][4];int main(){    bool flag=0;    for(int i=1;i<=4;++i)    {        for(int j=1;j<=4;++j)        {            scanf("%d",&a[i][j]);        }        if(a[i][4]&&(a[i][1]||a[i][2]||a[i][3])) flag=1;    }    if(a[1][4]&&(a[2][1]||a[3][2]||a[4][3])) flag=1;    if(a[2][4]&&(a[1][3]||a[3][1]||a[4][2])) flag=1;    if(a[3][4]&&(a[2][3]||a[4][1]||a[1][2])) flag=1;    if(a[4][4]&(a[1][1]||a[3][3]||a[2][2]))  flag=1;    if(flag) printf("YES\n");    else printf("NO\n");    return 0;}


B题:http://codeforces.com/contest/812/problem/B

题意:一个人从图的左下角出发,每次到上一层必须经过最左边点或者最右边的点,每走一格需要一个的时间,问怎么样才能遍历所有的1.

做法:

1.直接dfs记录当前的位置以及所用的时间,这里的vis最多走两遍,所以当vis为0,1的时候都可以走。然后剪剪枝就行了,当时先用的dfs做的,然后读地图的时候读错了,以为自己的dfs炸了。就换了下面的做法

2.细细一想这似乎可以用dp啊。

dp[i][0] 到当前楼最左边的最小步数           dp[i][1] 到当前楼最右边的步数   i代表着层数

所以会有这样的转移方程,l[i] ,r[i]分别表示这层楼最左边的1,和最右边的1. m+2是这层楼的长度

dp[i][0]=min(dp[i+1][0]+2*r[i+1]+1,dp[i+1][1]+m+2);
dp[i][1]=min(dp[i+1][0]+m+2,dp[i+1][1]+2*(m+1-l[i+1])+1);

这个时候细心的人就会发现:

1.如果走到当前层,上面的所有层都没有1了dp不就应该停了么!!!

2.如果走到当前层,这层没有1。就应该直接去上一层呀。

因为这两点比赛的时候wa了五六回,补题的时候又弄了几个小时!!!


#include <iostream>#include<stdio.h>#include<string.h>using namespace std;int main(){    int n,m;    int dp[20][2];    int l[20],r[20];    int lig[20];    memset(l,0,sizeof(l));    memset(r,0,sizeof(r));    memset(dp,0,sizeof(dp));    memset(lig,0,sizeof(lig));    scanf("%d%d",&n,&m);    char s[105];    int sum=0;    for(int i=1;i<=n;++i)    {        scanf("%s",s);        int len=strlen(s);        for(int j=0;j<len;++j)        {            if(s[j]=='1')            {                sum++;                lig[i]++;                if(l[i]==0) l[i]=j;                r[i]=j;            }        }    }    int pos=0;    for(int i=1;i<=n;++i)    {        if(lig[i]!=0)        {            pos=i; break;        }    }    if(pos==n)    {        printf("%d\n",r[pos]);        return 0;    }    dp[n-1][0]=2*r[n]+1; dp[n-1][1]=m+2;    for(int i=n-2;i>=1;--i)    {      if(lig[i+1]==0)      {          dp[i][0]=dp[i+1][0]+1; dp[i][1]=dp[i+1][1]+1;      }      else      {           dp[i][0]=min(dp[i+1][0]+2*r[i+1]+1,dp[i+1][1]+m+2);           dp[i][1]=min(dp[i+1][0]+m+2,dp[i+1][1]+2*(m+1-l[i+1])+1);      }      if(i==pos) break;    }    printf("%d\n",min(dp[pos][0]+r[pos],dp[pos][1]+(m+1-l[pos])));    return 0;}

C http://codeforces.com/contest/812/problem/C

题意:有一定的商品每件商品都有一个初始价格,和一个标号。你有s块钱,当你购买k件物品时,每个物品的价钱变成 初始价钱+ 标号乘以k。

做法:二分,每次判断的时候就给开个数组算下当前的价格排序,判断一下可以是否可以购买这么多件物品。


感觉自己的二分写完总是大于答案1或者等于答案,郁闷啊,有没有大神指点一下

#include<bits/stdc++.h>using namespace std;int a[100100];int b[100100];int s,n;bool judge(int mid){    if(mid>n) return 0;    int cost=s;    for(int i=0;i<n;++i)    {        b[i]=a[i]+(i+1)*mid;    }    sort(b,b+n);    for(int i=0;i<mid;++i)    {        cost=cost-b[i];        if(cost<0) return 0;    }    if(cost<0) return 0;    return 1;}int main(){    memset(a,0,sizeof(a));    scanf("%d%d",&n,&s);    for(int i=0;i<n;++i)    {        scanf("%d",&a[i]);    }    int l=0,r=n;    long long ans=0;    while(l<r)    {        int mid=l+(r-l)/2;        if(judge(mid)) l=mid+1;        else r=mid-1;    }    while(judge(l)==0) l--;    for(int i=0;i<n;++i) b[i]=a[i]+(i+1)*l;    sort(b,b+n);    for(int i=0;i<l;++i) ans=ans+(long long)b[i];    printf("%d %I64d\n",l,ans);    return 0;}









原创粉丝点击