zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 97 (Rated for Div. 2)

    太菜了,卡在C上以至于没有看到D。


    A. Marketing Scheme

    题意:如果 x mod a ≥ ⌊a/2⌋,那么这是好的。问在x∈[l,r]时,能否找到一个a,使得对于区间内任意的x都是好的。

    对于区间左端点,a能取得的最大的情况,就是a=2*l了,那么只要r小于2*l就成立。

    B. Reverse Binary Strings

    题意:翻转01串,使之变成01交题串

    两种理解:

    1、翻转一次不会造成内部的变化,只改变首尾两点。那么我们找多少个需要被交换的0或者1就行了。

    比如(111)那么就有两个1需要被翻转走,需要被交换的01个数取大就好。

            int  cnt1 = 0, cnt2 = 0;
            for(int i=1;i<s.length();++i)(
            {
                if(s[i]==s[i-1])
                {
                    if(s[i]=='1') cnt1++;
                    else cnt2++;
                }
            }
            cout<<max(cnt2,cnt1)<<endl;

    2、目标串只有101010以及010101的形式,所以,既然翻转一次内部方向改变,内部交替不变,那么我再换一次内部就好了。

    比如11101000的目标是10101010,那么只有2和6号位不匹配,那么我翻转2-6,再翻转3-5就能达成目标。

    对于目标是101010,但当中的四位0101都不匹配,那么我只用翻转一次就好。

    这时候就会有一个问题?当前串01010不匹配呢,翻转也不行的啊?考虑到其他地方会多一个1不匹配,所以不计也没关系。

    那么如果一定要多次操作才能还原后面的1呢?那这时候目标串是010101不是更好吗。

    证明不是很严谨,当时是看到队友a了,急中生智,看了一下跟别人的解法都不一样。

    可能是错的。

    memset(vis,0,sizeof(vis));
            ans=anss=0;
            scanf("%d",&n);
            scanf("%s",a+1);
            //10101010
            f=1;
            for(int i=1;i<=n;++i){
                if(a[i]-'0'==f){
                    
                }
                else{
                    ans++;
                    if(!vis[i])    vis[i]=1;  //需要被交换
                    if(vis[i-1])    ans--;   //前面一位也被交换,当前位不计贡献
                }
                f^=1;
            }
            memset(vis,0,sizeof(vis));
            f=0;
            for(int i=1;i<=n;++i){
                if(a[i]-'0'==f){
                    
                }
                else{
                    anss++;
                    if(!vis[i])    vis[i]=1;
                    if(vis[i-1])    anss--;
                }
                f^=1;
            }
            ans=min(ans,anss);
            printf("%d
    ",ans);

    C. Chef Monocarp

    题意:一分钟只能出一个餐,一开始所有餐都在烤炉里,每次出餐贡献+|t[i]−T|(T为当前时间),问让总贡献最小的方法。
    (注:出餐时间不一定连续。

    很显然是一个dp题,但是我没想到方程怎么写。

    dp[i][j]表示第i号餐在j时间出来的最优解。

    先排个序,因为时间是线性增长的,t[i]线性增长更优。

    代码来自一位dalao

    int dp[270][270*2],a[270],t,n;
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
            memset(dp,0x7f,sizeof(dp));
            for(int i=0;i<=2*n;++i)    dp[0][i]=0;
            sort(a+1,a+1+n);
            for(int i=1;i<=n;++i){
                for(int j=i-1;j<=2*n;++j){
                    for(int k=j+1;k<=2*n;++k){
                        dp[i][k]=min(dp[i][k],dp[i-1][j]+abs(a[i]-k));
                    } 
                } 
            }
            int ans=inf;
            for(int i=n;i<=2*n;++i)    ans=min(ans,dp[n][i]);
            printf("%d
    ",ans);
        }
        return 0;
    } 

    D. Minimal Height Tree

    题意:给定树的bfs序,对任意节点的子节点按升序排列,问最小高度是多少?

    如果理解不了,我就来画个图吧。

    两个都是1 4 5 2 3的遍历顺序,明显第一幅图更优。

    先看一下代码

    int t,a[200007],q[200007],p,n;    //q记录每层的个数
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);
            memset(q,0,sizeof(q));
            q[0]=1;p=1;
            for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
            for(int i=2;i<=n;++i){
                if(a[i]>a[i-1]){    //升序就加入当前层
                    q[p]++;
                }
                else if(q[p-1]>1){   //看一下上一层子结点个数大于1,挂到上层那个点
                    q[p-1]--;
                    q[p]++;
                }
                else if(q[p-1]==1){   //上层个数==1,说明,上层已经没有空间加了
                    p++;
                    q[p]++;
                }
            }
            printf("%d
    ",p);
        }
        return 0;
    } 

    还理解不了就对图跑一遍,记住节点的子结点都必须升序。

    E. Make It Increasing

    感谢该博主https://www.cnblogs.com/werner-yin/p/solution-CF-1437E.html的题解。

    以下会对该博主的代码加上自己的注释和理解,便于观看。建议点开双开。

    #include<cstdio>
    #include<cmath> 
    #include<iostream> 
    #include<cstring> 
    #include<algorithm>
    #include<stack>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    #include<iomanip>
    #define inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    const int N= 1e6+7;
    int a[N],b[N],lock[N],d[N],last=0,pos=0,n,k;
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=k;++i){
            scanf("%d",&b[i]);
            lock[b[i]]=1;
        }
        sort(b+1,b+1+k);
        for(int i=1;i<k;++i)
            if(a[b[i]]-b[i]>a[b[i+1]]-b[i+1]){    //保证后一位锁定位之差大于前一位锁定位之差 
                printf("-1
    ");                    //因为严格上升,且上升的差值大于等于1 
                return 0;                        //比如三号位和六号位被锁,那么4 6的值是不合法的 
            }
        /*
            要求的是改几个位子使之成为严格上升序列。
            按一般的思路,找一下最长的严格上升子序列。
            原长度-找到的长度就行。
            但是这样有一个问题,我们不能保证找的子序列中间能改出来。
            比如样例一,我们能找到1 2 3 5.但是 2 3 之间的两个1 我们没有办法。
            所以我们先减去当前位的值。使之满足严格
            然后找最长不下降就行了。 
        
        */ 
        for(int i=1;i<=n;++i)    a[i]-=i;        //保证严格上升,且上升的差值大于等于1 
        for(int i=1;i<=n;++i){
            if(pos==0||a[i]>=d[pos]){
                d[++pos]=a[i];
                if(lock[i])    last=pos;        //如果新加入的点是锁定位,标记他 
            }
            else{
                int p= upper_bound(d+1,d+1+pos,a[i])-d;
                if(p<=last)    continue;    //如果找到替换位置在最后一个锁定位之前 
                d[p]=a[i];                //那么如果更换了,锁定就消失了。所以不能更换。 
                if(lock[i])    last=p,pos=p;
            }
        }
        printf("%d
    ",n-pos);
        return 0;
    }
  • 相关阅读:
    Java中的transient关键字
    【笔记】html的改变(上)
    《开发板 — 实现看门狗》
    《头文件导致Symbol xxx multiply defined重复定义问题分析和解决》
    《APP读取按键值》
    《补充 — Linux内核device结构体分析(转)》
    《设备树LED模板驱动程序》
    《C库 — 字符串和整型数相互转换函数atoi和itoa》
    《Ubuntu — rsync命令》
    《Ubuntu — 2>/dev/null和>/dev/null 2>&1和2>&1>/dev/null的区别》
  • 原文地址:https://www.cnblogs.com/PdrEam/p/13898961.html
Copyright © 2011-2022 走看看