• CS Academy Round#5 E.Binary Matching


    题目链接

    CsAcademy Beta Round #5 Binary Matching

    题目大意

    有俩 (01)(a)(b),你需要把 (a) 中的一些相邻元素互换,使得 (b)(a) 匹配的次数尽量多,求最大的匹配次数以及达到这个状态所需的最少步数。

    串的长度 (in[1, 500])

    思路

    如果你的思路是这样的:“最大匹配次数好像很好求,我先把这个求出来,然后构造个串 (c)(a) 求最少步数应该就可以了。” 那么真巧,你跟我开始一样误入歧途了,其实 (c) 这个串具有很大的灵活性,算起来相当麻烦。

    讲正确的做法,要 (dp) 的话我们从前往后扫 (a),这是一个类似于 (KMP)(b) 匹配的过程,那么应该可以想到这样一个状态:(dp[i][j][k]=(max\_matchings,min\_operations))(i)(j) 表示当前有的 (0)(1) 的个数,(k) 表示匹配到了 (b) 的第 (k) 位,转移时枚举下一位是 (0) 还是 (1),找到下一个状态的 (k) 直接做 (KMP),步数看当前的 (1)(a) 中 对应的 (1) 的距离即可(如果是 (0) 就不管)。

    时间复杂度: (O(n^3))

    不过呢,这题空间时间都卡,内存只有 (128 MB),需要滚动 (dp)。时限 (1000ms),可以预处理 (KMP) 中跳 (nxt) 的结果,对于达不到的状态直接 continue ,这样就可以最优解 rank 5 了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define mem(a,b) memset(a, b, sizeof(a))
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define per(i,b,a) for(int i = (b); i >= (a); i--)
    #define N 505
    #define PII pair<int, int>
    #define fr first
    #define sc second
    #define Inf 0x3f3f3f3f
    using namespace std;
    string a, b;
    PII dp[2][N][N];
    int n, m, nxt[N], loc[N], match[N][2];
    void kmp(){
        nxt[0] = 0;
        int j = 0;
        rep(i,1,m-1){
            while(j > 0 && b[i] != b[j]) j = nxt[j-1];
            if(b[j] == b[i]) j++;
            nxt[i] = j;
        }
    }
    void Trans(PII &a, PII b){
        if(a.fr < b.fr) a = b;
        else if(a.fr == b.fr) a.sc = min(a.sc, b.sc);
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>a>>b;
        n = a.size(), m = b.size();
    
        kmp();
        rep(i,0,m) rep(c,'0','1'){
            int tmp = i;
            while(tmp > 0 && b[tmp] != char(c)) tmp = nxt[tmp-1];
            if(b[tmp] == char(c)) tmp++;
            match[i][c-'0'] = tmp;
        }
        int cnt = 0;
        rep(i,0,n-1) if(a[i] == '1')
            loc[++cnt] = i;
    
        mem(dp, 0x80), dp[0][0][0] = {0, 0};
        rep(i,0,n-cnt) rep(j,0,cnt) rep(k,0,m){
            if(dp[i%2][j][k].fr < 0) continue;
            //printf("dp[%d][%d][%d] : %d %d
    ", i, j, k, dp[i%2][j][k].fr, dp[i%2][j][k].sc);
            rep(c,'0','1'){
                int tmp = match[k][c-'0'];
                PII cur = dp[i%2][j][k];
                cur.fr += (tmp == m);
                if(c == '0') Trans(dp[(i+1)%2][j][tmp], cur);
                if(c == '1') cur.sc += abs(loc[j+1]-(i+j)), Trans(dp[i%2][j+1][tmp], cur);
            }
            if(i%2 != (n-cnt)%2 || j != cnt) dp[i%2][j][k] = {-Inf, -Inf};
        }
    
        PII ans = {0, 0};
        rep(k,0,m) Trans(ans, dp[(n-cnt)%2][cnt][k]);
        cout<<ans.fr<<" "<<ans.sc<<endl;
        return 0;
    }
    

    吐槽一下这个网站上人的码风,一个 63 行代码就可以解决的题目,为什么大家都写了 100+ 行,其它题目也是的,很奇怪的长,我就不是很懂。。

  • 相关阅读:
    烂泥:jira7.2安装、中文及破解
    烂泥:VMWare Workation双网卡配置IP地址
    烂泥:centos6 yum方式升级内核
    烂泥:python2.7和python3.5源码安装
    烂泥:zabbix3.0安装与配置
    烂泥:利用awstats分析nginx日志
    烂泥:切割nginx日志
    JavaScript之函数
    Django之根据已经存在数据库中的表自动生成模型
    Django之操作数据库
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14732954.html
Copyright © 2020-2023  润新知