zoukankan      html  css  js  c++  java
  • Codeforces Round #545 (div 1.)

    B.Camp Schedule

    给两个 $01$ 串 $s$ 和 $t$,你可以将 $s$ 串任意重排,要求最大化 $t$ 在 $s$ 子串中出现的次数,可以重叠

    $|s|,|t| leq 500000$

    sol:

    看到可以重叠,考虑最大化利用重叠部分

    重叠部分是这次 $t$ 串的结束和下次 $t$ 串的开始,也就是 $t$ 串的一个 $border$

    先放一个 $border$ ,之后一直放 $t$ 串的除 $border$ 以外的部分就可以了

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -f;
        for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    char s[500010], t[500010], border[500010], ans[500010], pborder[500010];
    int fail[500010], cnt[2], pcnt[2], ncnt[2];
    int chk() {return (cnt[1] >= pcnt[1]) && (cnt[0] >= pcnt[0]);}
    int chk2() {return (cnt[1] >= ncnt[1]) && (cnt[0] >= ncnt[0]);}
    int main() {
        scanf("%s", s + 1); scanf("%s", t + 1);
        int n = strlen(s + 1), m = strlen(t + 1);
        rep(i, 1, n) cnt[s[i] - '0']++;
        int j = 0; for(int i=2;i<=m;i++) {
            while(j && t[j + 1] != t[i]) j = fail[j];
            if(t[i] == t[j + 1]) j++;
            fail[i] = j;
        } int blen = fail[m];
        rep(i, 1, blen) border[i] = t[i], pcnt[t[i] - '0']++;
        //cout << border+1 << endl;
        rep(i, blen+1, m) pborder[i - blen] = t[i], ncnt[t[i] - '0']++;
        //cout << pborder+1 << endl;
        int clen = strlen(pborder + 1);
        int dfn = 1;
        if(chk()) {
            cnt[1] -= pcnt[1]; cnt[0] -= pcnt[0];
            rep(i, 1, blen) ans[i] = border[i]; dfn = blen;
            while(chk2()) {
                rep(i, 1, clen)
                    ans[dfn + i] = pborder[i];
                dfn += clen;
                cnt[1] -= ncnt[1]; cnt[0] -= ncnt[0];
            }
            while(cnt[1]) {
                ans[++dfn] = '1';
                cnt[1]--;
            }
            while(cnt[0]) {
                ans[++dfn] = '0';
                cnt[0]--;
            }
            cout << (ans + 1) << endl;
        }
        else {
            cout << (s+1) << endl;
        }
    }
    /*1111111001100
    101*/
    View Code

    C.Museums Tour

    一个有向图,每个点有一个博物馆,每个博物馆有一个长度为 $d$ 的开放时间表(是循环的),你可以进行一次任意天的旅行,但是每天必须走一步,问最多能参观多少博物馆

    $n,m leq 100000,d leq 50$

    sol:

    卡空间神题,卡掉了 w imes h

    虽然他还是 rank 1.

    有很多基于强连通分量的做法,这里写一种比较稳的

    把每个点拆成 $d$ 个点,求一个强连通分量

    在强连通分量里算一下有哪些点可以走到即可,显然只需要 $(x,y)$ 这个点在强连通分量里且 $x$ 在第 $y$ 天开放就可以通过一直绕圈圈走到

    外面是个 DAG,做个 dp 即可

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -f;
        for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 5000010;
    int n, m, d;
    int first[maxn], to[maxn], nx[maxn], cnt;
    inline void add(int u, int v) {
        to[++cnt] = v;
        nx[cnt] = first[u];
        first[u] = cnt;
    }
    int dfn[maxn], low[maxn], st[maxn], top, bl[maxn], scc, _tim;
    char grid[100010][60];
    int now;
    vector<int> G2[maxn], ccs[maxn];
    inline void Tarjan(int x) {
        dfn[x] = low[x] = ++_tim; st[++top] = x;
        for(int i=first[x];i;i=nx[i]) {
            if(!dfn[to[i]]) {
                Tarjan(to[i]);
                low[x] = min(low[x], low[to[i]]);
            }
            else if(bl[to[i]] == -1) low[x] = min(low[x], dfn[to[i]]);
        }
        if(low[x] == dfn[x]) {
            now = -1;
            do {
                now = st[top--];
                bl[now] = scc;
                ccs[scc].push_back(now);
            }while(now != x);
            scc++;
        }
    }
    int dp[maxn], hsh[maxn];
    int main() {
        n = read(), m = read(), d = read();
        memset(bl, -1, sizeof(bl));
        rep(i, 0, m-1) {
            int u = read() - 1, v = read() - 1;
            rep(j, 0, d-1) add(u * d + j, v * d + (j + 1) % d);
        }
        rep(i, 0, n-1) scanf("%s", grid[i]);
        rep(i, 0, n-1) rep(j, 0, d-1) grid[i][j] -= '0';
        rep(i, 0, n*d-1) if(!dfn[i]) Tarjan(i);
        rep(i, 0, scc-1) {
            sort(ccs[i].begin(), ccs[i].end());
            int last = -1;
        //    cout << i << ":" << endl;
        //    for(auto j : ccs[i]) cout << j << " ";
        //    cout << endl;
            for(auto j : ccs[i]) {
                if(j / d != last) { 
                    if(grid[j / d][j % d]) {
                        //cout << last << ":" << j << " " << d << endl;
                        hsh[i]++;
                        last = j / d;
                    }
                }
            }
        }
        rep(x, 0, n*d-1)
            for(int i=first[x];i;i=nx[i])
                if(bl[x] != bl[to[i]]) 
                    G2[bl[x]].push_back(bl[to[i]]);
                    //cout << bl[x] << "->" << bl[to[i]] << endl;
                    //ind[bl[to[i]]]++;
        //rep(i, 0, scc-1) cout << hsh[i] << " ";
        rep(i, 0, scc-1) {
            dp[i] = hsh[i];
            for(auto h : G2[i]) dp[i] = max(dp[i], dp[h] + hsh[i]);
        }
        cout << dp[bl[0]] << endl;
    }
    View Code

    D.Cooperative Game

    交互题

    有一个链表,已知它有闭环,你一开始有 $10$ 个指针,都指向表头

    每次操作你可以让若干个指针向前移动一个单位,交互器会返回现在哪些指针在同一个单位

    你现在要让所有指针都正好在环的起始节点,并在都在环的起始节点时输出 $done$

    操作次数限制为 $3n$ 次,你不知道环长,不知道链长,甚至不知道 $n$

    $n leq 1000$

    sol:

    经典题...网上都是解法但我没搜

    经典解法是这样的:

    1.设置一个“快节点”,一个“慢节点”,快节点每次走两步,慢节点每次走一步

    (具体到这道题就是第一步让他俩一起走,第二步只有快节点走)

    2.这两个点如果相遇,说明链表有环

    (这题一定有)

    3.再把两个节点一个放回表头,另外一个在相遇点不动,把这两个点一起动,相遇的地方就是环的起始节点

    (这题你相遇点有两个点,然后你惊喜的发现起始节点还有 8 个点没动,那就大家一起走就可以了)

    4.输出 done,Pretest Passed,Accepted,然后大骂出题人

    考验大家使用 Google / wiki 能力?

    Stop Writing Problems

    #include<bits/stdc++.h>
    #define LL long long
    #define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i)
    #define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read() {
        int x=0,f=1;char ch;
        for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
        for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
        return x*f;
    }
    const int maxn = 100010;
    string ch;
    int getres() {
        int x; cin >> x;
        rep(i, 1, x) cin >> ch;
        return x;
    }
    int main() {
        do {
            cout << "next 0 1" << endl; getres();
            cout << "next 0" << endl;
        }while(getres() > 2);
        do {
            cout << "next 0 1 2 3 4 5 6 7 8 9" << endl;
        }while(getres() > 1);
        cout << "done" << endl;
    }
    View Code
  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10499605.html
Copyright © 2011-2022 走看看