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
  • 相关阅读:
    ZooKeeper的工作原理
    redis 数据类型详解 以及 redis适用场景场合
    nginx负载均衡原理
    Java中缓存的介绍
    Java中接口的作用
    json与xml的区别
    最经典40个多线程问题总结
    Java线程 : 线程同步与锁
    dbcp与c3p0的区别
    Linux常见命令
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10499605.html
Copyright © 2011-2022 走看看