• 「日常训练」Alternative Thinking(Codeforces Round #334 Div.2 C)


    题意与分析 (CodeForces - 603A)

    这题真的做的我头疼的不得了,各种构造样例去分析性质。。。
    题意是这样的:给出01字符串。可以在这个字符串中选择一个起点和一个终点使得这个连续区间内所有的位取反。求经过处理后最多会得到多少次01变换(可以不连续)。
    首先求原串的最长01长度,这个太简单了,然后才是重头戏:精彩的构造样例分类讨论环节——如何增加01的最长串?
    我们考虑一下反转串的几种情况:1、反转单个连续0/1串的内部;2、反转两个部分连续0/1串与中间的内容(内部无连续串)3、反转两个部分连续0/1串与中间的内容(内部有连续串)4、反转连续01串(不是0/1串!)
    第一种情况是最好考虑的,不论你是1000..0001还是0111...11110,里面不论怎么反转,最后对答案的贡献也多一个01/10,也就是2。这种多的贡献仅仅出现在0/1串长度大于等于三的情况。
    第二种情况稍微复杂一些:先考虑0开头的情况,也就是00..0{101010101}1..11或者00..0{101010101}0..00。这种情况下最好的处理是连着前后一个字符一起反转:00..1{010101010}0..11于是长度喜多2。这种情况下,前面跟着一个串(长度大于等于2即可)就产生1的贡献,后面跟着一个就产生一个贡献。1开头的同理。
    第三种情况建立在2的基础上:如果反转串中间也有连续会怎样?什么时期都不会发生,因为它作出的贡献仅仅相当于一个单个字符。于是答案同2。
    第四种情况比较有趣了:我对原答案做反转,没有连续的01会怎样?那你不管怎么样,最优答案总是原先的最长长度。

    综合以上四种情况,我们可以得到这个结论:
    如果整个串里面的00/11串个数(le 2),那么答案(即原先长度)加上这个串的个数;否则答案最多+2。情况1此时已经被包括在内了,因为长度为3的连续串一定有两个00/11串。

    代码

    /* 
     * Filename: cfr334d2c.cpp
     * Date: 2018-11-05
     */
    
    #include <bits/stdc++.h>
    
    #define INF 0x3f3f3f3f
    #define PB emplace_back
    #define MP make_pair
    #define fi first
    #define se second
    #define rep(i,a,b) for(repType i=(a); i<=(b); ++i)
    #define per(i,a,b) for(repType i=(a); i>=(b); --i)
    #define ZERO(x) memset(x, 0, sizeof(x))
    #define MS(x,y) memset(x, y, sizeof(x))
    #define ALL(x) (x).begin(), (x).end()
    
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
    
    using namespace std;
    using pi=pair<int,int>;
    using repType=int;
    using ll=long long;
    using ld=long double;
    using ull=unsigned long long;
    
    int dp[100005][2];
    
    int
    main()
    {
        int n; cin>>n;
        bool b[100005];
        string str; cin>>str;
        int maxlen=0,nowlen=0;
        bool last;
        int cnt=0;
        rep(i,0,n-1)
        {
            b[i+1]=str[i]=='0';
            if(i==0)
            {
                dp[i+1][0]=str[i]=='0';
                dp[i+1][1]=str[i]=='1';
                last=b[i+1];
                nowlen=1;
            }
            else
            {
                if(last==b[i+1])
                {
                    nowlen++;
                    maxlen=max(nowlen,maxlen);
                }
                else
                {
                    cnt+=nowlen-1;
                    nowlen=1;
                    last=b[i+1];
                }
                if(str[i]=='0')
                {
                    dp[i+1][1]=dp[i][1];
                    dp[i+1][0]=dp[i][1]+1;
                }
                else
                {
                    dp[i+1][1]=dp[i][0]+1;
                    dp[i+1][0]=dp[i][0];
                }
            }
        }
        if(nowlen!=1) cnt+=nowlen-1;
        int ans=0;
        rep(i,1,n)
            ans=max(ans,max(dp[i][0],dp[i][1]));
    /*
        rep(i,1,n)
            cout<<dp[i][0]<<" ";
        cout<<endl;
        rep(i,1,n)
            cout<<dp[i][1]<<" ";
        cout<<endl;
    */
        cout<<ans+min(2,cnt)<<endl;
        return 0;
    }
    
    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    对 Excel 工作簿中的数字签名和代码签名的说明
    单例模式
    面向对象
    Des对称加密
    Java获取电脑硬件信息
    鼠标双击事件不可描述的问题
    RSA不对称加密
    JTable表格案例
    控件刷新的奥秘
    反编译插件安装
  • 原文地址:https://www.cnblogs.com/samhx/p/CFR334D2C.html
Copyright © 2020-2023  润新知