• USACO07 MAR Face The Right Way G


    疫情当下,美帝又开始倒牛奶了,这一幕似曾相识啊~~~

    这个题目非常的应景,又是美国佬的奶牛

    【题目地址】

    【一句话题意】

    N头牛排成一列1<=N<=5000。每头牛或者向前或者向后。
    为了让所有牛都 面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,
    求操作的最少次数M和对应的最小K。

    【Input】

    第1行:单个整数:N
    第2..N + 1行:第i + 1行包含单个字符F或B,指示母牛i面向前还是面向后。

    【Output】

    第1行:两个以空格分隔的整数:K和M

    【Sample】

    input
    7
    B
    B
    F
    B
    F
    B
    B
    
    output
    3 3
    

    【分析&思路】

    区间修改?
    线段树、树状数组,暴力枚举01修改——boom
    我们注意到每一个点只有两种状态0|1
    那么如果修改两次的话就相当于没改咯
    我们把区间分开考虑
    怎么说
    就是把最左边连续的一段进行操作变为全部向前
    于是在后续的操作中我们duck不必再考虑前面的
    这思路没啥问题,直接上暴力

    #include <cstdio>
    using namespace std;
    int n, a[5005][5005], minn = 99999, step , pin;
    
    int main(){
        scanf("%d",&n);
        for(int i = 1; i <= n; i++){
            char ch;
            getchar();
            ch = getchar();
            if(ch == 'B') a[0][i] = 0;
            else a[0][i] = 1;
        }
        for(int i = 1; i <= n; i++){
            step = 0;
            int flag = 0;
            for(int j = 1; j <= n; j++)
            a[i][j] = a[0][j];
            for(int j = 1; j <= n - i + 1; j++){
                if(!a[i][j]){
                for(int k = 0; k < i ; k++){
                    a[i][j + k] ^= 1;
                }
                step++;
                if(step > minn) break;
                }
            }
            for(int j = n - i + 2; j <= n; j++){
                if(!a[i][j]){
                    flag = 1;
                    break;
                }
            }
            for(int j = 1; j <= n; j++)
            if(!flag) {
                if(minn > step)
                {
                    minn = step;
                    pin = i;
                }
            }
        }
        printf("%d %d", pin, minn);
        return 0;
    } 
    

    然后……T掉了……
    那么我们再来考虑优化的方法
    类似于差分
    在此,可能叫做“异或分”
    记录区间长度为k
    每次反转的时候更改标记为0或1
    给两个区间分别异或
    则不改变前后区间的相对状态
    总的时间复杂度为(O(n^2))
    emmmmm就这样叭
    代码非原创

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 10009;
    int n;
    bool A[maxn],B[maxn];
    int main(){
        scanf("%d",&n);
        char ch;
        for(int i=1;i<=n;++i){
            cin>>ch;A[i]=ch=='B'?0:1;
        }
        int mincnt=0x7fffffff,anslen;
        for(int len=1;len<=n;++len){
            memset(B,0,sizeof B);
            bool b=0,flag=1;int cnt=0;//flag记录当前长度是否有解
            for(int i=1;i<=n;++i){//因为区间翻转只有状态0和1,所以用^代替+和-
                b^=B[i];//数组B为记录差分的数组
                if(!(A[i]^b)){//若当前位置为0
                    if(i+len-1>n){flag=0;break;}//唯一的失败条件:一次翻转的长度大于剩余的长度
                    b^=1,B[i+len]^=1;
                    ++cnt;
                }
            }
            if(flag){if(cnt<mincnt)mincnt=cnt,anslen=len;}
        }printf("%d %d
    ",anslen, mincnt);
    } 
    
    风吹过,我来过~
  • 相关阅读:
    守护线程与普通线程
    Java中实现多线程的两种方式之间的区别
    Python os.dup() 方法
    Python os.closerange() 方法
    Python os.close() 方法
    Python os.chroot() 方法
    Python os.chmod() 方法
    JavaScript——基本包装类型
    javascript——function类型(this关键字)
    常用的正则
  • 原文地址:https://www.cnblogs.com/rui-4825/p/12642272.html
Copyright © 2020-2023  润新知