Educational Codeforces Round 106 (Rated for Div. 2)(A~C)(DP)

三题滚粗。(至少现在可以稳3题了呜呜)

A.Domino on Windowsill

本题是贪心的思想。如果第一行和第二行白色块的个数相同,那么全摆成竖的。白色块的数量最多为k1.如果不同就看他们之间的差值为多少,那么就能在插入差值除以2个白色块。即min(k1,k2)+abs(k1-k2)/2.黑色块同理

AC代码如下:

#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<set>
#define MAXN 10000005
using namespace std;
typedef long long ll;
int t,n,k1,k2,w,b;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d%d",&n,&k1,&k2,&w,&b);
        int flag=0;
        int len1=max(k1,k2)-min(k1,k2);
        if(k1==k2){
            if(w<=k1)
                flag=1;
        }else
            if(w<=min(k1,k2)+len1/2)
                flag=1;
        if(flag){
            k1=n-k1;
            k2=n-k2;
            len1=max(k1,k2)-min(k1,k2);
            if(k1==k2){
                if(b<=k1){
                    printf("YES\n");
                    continue;
                }
            }else
                if(b<=min(k1,k2)+len1/2){
                    printf("YES\n");
                    continue;
                }
        }
        printf("NO\n");
    }
    return 0;
}

B.Binary Removals

因为可以删不相邻的两个数,故对于101这种我们只需要留0即可。但我们也可以想到对于00这样的数就只能留0,对于11这样的数我们就只能留1。故当11出现在00之前时,就无法满足要求。因此只要判断是否存在11且11后面是否存在00即可。

AC代码如下:

#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<set>
#define MAXN 10000005
using namespace std;
typedef long long ll;
int t;
char s[105];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        int len=strlen(s);
        bool flag=0;
        for(int i=1;i<len;i++){
            if(!flag){
                if(s[i]==s[i-1]&&s[i]=='1')
                    flag=1;
            }else if(s[i]==s[i-1]&&s[i]=='0'){
                flag=2;
                printf("NO\n");
                break;
            }
            if(i==len-1)
                printf("YES\n");
        }
    }
    return 0;
}

C.Minimum Grid Path(DP)

可以选择向右或向上,每次转向后走路的花费都会变。但是不难看出向右和向上是独立。故花费可以通过奇偶性分割成独立的两部分。我们令dp[i],为转向1~i次时到达终点的最小花费。那么就是令其中除了花费最小的那次其他都只走1步,剩下的由花费最少的那次走完即可。所以我们只需要找dp[i]+dp[i-1]的和最小的值即可。

AC代码如下:

#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<set>
#define MAXN 100005
using namespace std;
typedef long long ll;
int t,n;
ll dp[MAXN];//��ʾ��һ������ֻתi�Σ�����Ҫ�����ٲ��� 
ll c[MAXN];//��ʾһ��ת�����·�Ļ��ѡ�
ll pre[MAXN]; //ǰ��c1~ci��ǰ׺�� 
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        scanf("%d",&c[1]);
        ll min1=c[1],min2=1e10;
        dp[1]=c[1]*n,dp[0]=0;
        pre[1]=c[1],pre[0]=0;
        int minans1,minans2;
        for(int i=2;i<=n;i++){
            if(i&1){
                scanf("%d",&c[i]);
                pre[i]=pre[i-2]+c[i];
                if(min1>c[i]){
                    min1=c[i];
                    dp[i]=pre[i-2]+min1*(n-i/2);
                }else
                    dp[i]=dp[i-2]-min1+c[i];
            }else{
                scanf("%d",&c[i]);
                pre[i]=pre[i-2]+c[i];
                if(min2>c[i]){
                    min2=c[i];
                    dp[i]=pre[i-2]+min2*(n-i/2+1);
                }else
                    dp[i]=dp[i-2]-min2+c[i];
            }
        }
        ll ans=dp[1]+dp[2];
        for(int i=1;i<=n-1;i++){
            if((dp[i]+dp[i+1])<ans)
                ans=dp[i]+dp[i+1];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2021-03-25 21:38  mikku  阅读(48)  评论(0)    收藏  举报