zoukankan      html  css  js  c++  java
  • 省选测试16

    好久没有考场上 A题了

    A 环

    题目大意 : 构造出一个 01 序列使得存在一个 1 满足这个 1 后面是 0,且这个 1 和后面的 0 交换后与原序列循环同构

    • 你要移动一个数让他还是循环同构
    • 比如说样例 101011010101 移动了第4个1他就循环同构了, 因为每次都移动的是1,所以按1分开
    101011010101
    2  2  12  2  2  1
    
    • 移动一下
    101010110101
    2  2  2  12  2  1
    
    • 发现也就是让下面那个2212221循环同构,把这个换成01串
    1101110
    12  112
    
    • 移动
    1110110
    112  12
    
    • 发现还是让下面那个循环同构
    • 设一共n个数,让k个数为1,然后就发现下面那个序列就是一共k个数,让n%k个数为1,递归找就行
    • 找到了一个构造就好说了,我直接就枚举了整体移动多少位,然后暴力判断

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    const int N = 105;
    
    int a[N], b[N], p[N];
    
    void Solve(int l, int k) {
        if (!k) return a[1] = -1, void();
        if (k == 1) return a[1] = 1, void();
        Solve(k, l % k);
        if (a[1] == -1) return;
        memcpy(b + 1, a + 1, k * 4);
        int cnt = 0, tmp = l / k;
        for (int i = 1; i <= k; ++i) {
            a[++cnt] = 1;
            for (int j = b[i] + tmp - 1; j; --j)
                a[++cnt] = 0;
        }
    }
    
    bool Judge(int l) {
        int cnt = 0;
        for (int i = 1; i <= l && cnt <= 2; ++i)
            if (a[i] != b[i]) p[++cnt] = i;
        int x = p[1], y = p[2];
        if (cnt != 2) return 0;
        if (x + 1 == y && b[x] && !b[y] && !a[x] && a[y]) return 1;
        if (x == 1 && y == l && !b[x] && b[y] && a[x] && !a[y]) return 1;
        return 0;
    }
    
    void Next(int l) {
        memcpy(b + 1, a + 1, l * 4);
        for (int d = 0; d < l; ++d) {
            for (int i = 1; i <= l; ++i)
                a[(i+d-1)%l+1] = b[i];
            if (Judge(l)) return;
        }
    }
    
    int main() {
        int T; scanf("%d", &T);
        while (T--) {
            int l, k, n; 
            scanf("%d%d%d", &l, &k, &n);
            memset(a, 0, sizeof(a));
            Solve(l, k);
            if (a[1] == -1) puts("NO");
            else {
                puts("YES");
                while (n--) {
                    for (int i = 1; i <= l; ++i)
                        printf("%d", a[i]);
                    puts("");
                    Next(l);
                }
            }
        }
        return 0;
    }
    

    B DNA序列

    题目大意 : 给定 n 个字符串,每个串选一个前缀,以任意顺序拼起来,令得到的串字典序最小

    • 考虑依次区的部分分,很容易想到从前往后贪心的选择前缀,发现这样是不对的,正确的应该是从后往前贪。复杂度n的4次方

    • 然后就是看什么样的顺序可以贪心成功

    • 题解上就是找到一个最短的前缀x,使得x重复无限次后字典序比原串小

    • 然后找到一个后缀y,满足x不是y的前缀

    • 排序把x当作第一关键字从小到大排序,把y当作第二关键字从大到小排序,然后贪心就好了

    Code

    Show Code
    #include <string>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N = 55;
    
    int n;
    string ans;
    
    struct Node {
        string s, x, y;
    }a[N];
    
    bool operator < (const Node &a, const Node &b) {
        return a.x != b.x ? a.x < b.x : a.y > b.y;
    }
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i].s; a[i].s += 'Z';
            int len = a[i].s.size(), x, y;
            for (x = 1; x <= len; ++x) {
                string tmp = a[i].s.substr(0, x), s;
                for (int j = 1; j <= 50; ++j) s += tmp;
                if (s < a[i].s) break;
            }
            a[i].x = a[i].s.substr(0, x); y = x;
            while (a[i].s.substr(y, x) == a[i].x) y += x;
            a[i].y = a[i].s.substr(y); 
            for (int j = 1; j <= 6; ++j)
                a[i].x += a[i].x;
        }
        sort(a + 1, a + n + 1);
        for (int i = n; i >= 1; --i) {
            int len = a[i].s.size();
            string lt = ans;
            ans = a[i].s[0] + ans;
            for (int j = 2; j <= len; ++j)
                ans = min(ans, a[i].s.substr(0, j) + lt);
        }
        cout << ans;
    }
    

    C 探寻

    题目大意 : 给定一颗树,第一次经过一条边有花费,第一次到达一个点会有收益,问从根到终点最小透支多少

    • 首先把终点的收益设为inf,这样就可以去贪心的找了

    • 对每个节点按费用从小到大排序,如果收益是负数的话就放在后面

    • 考虑取出一个点 x,找到 x 的祖先中第一个没有被选过的点 fx

    • 如果 fx 不存在,说明 x 可以被直接选

    • 如果有 fx,就把 x 和 fx 合并到一个点

    • 如果 w[fx] > c[x], 说明走父节点所拿的钱足够走到 x,就让 fx 的收益加上 w[x] - c[x]

    • 否则走父节点的代价还会增多,就让 fx 的代价加上 c[x] - w[fx],fx 的收益就变成了 w[x]

    Code

    Show Code
    #include <set>
    #include <cstdio>
    
    using namespace std;
    const int N = 2e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar())
            if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar())
            x = x * 10 + c - '0';
        return x * f;
    }
    
    bool v[N];
    int n, fa[N], f[N]; 
    long long w[N], c[N], ans, sum;
    
    int Find(int x) {
        return x == f[x] ? x : f[x] = Find(f[x]);
    }
    
    bool Cmp(int x, int y) {
        return (w[x] > c[x]) != (w[y] > c[y]) ? w[x] > c[x] : (c[x] != c[y] ? c[x] < c[y] : x < y);
    }
    
    set<int, bool(*)(int, int)> s(Cmp);
    
    int main() {
        n = read(); v[0] = 1;
        for (int i = 1; i < n; ++i) {
            fa[i] = read(), w[i] = read(), c[i] = read();
            if (w[i] == -1) w[i] = 1e15;
            s.insert(i); f[i] = i;
        }
        while (!s.empty()) {
            int x = *s.begin(); s.erase(s.begin());
            v[x] = 1; f[x] = fa[x];
            int fx = Find(x);
            if (v[fx]) ans = min(ans, sum -= c[x]), sum += w[x];
            else {
                s.erase(s.find(fx));
                if (w[fx] > c[x]) w[fx] += w[x] - c[x];
                else c[fx] += c[x] - w[fx], w[fx] = w[x];
                s.insert(fx);
            }
        }
        printf("%lld
    ", -ans);
        return 0;
    }
    
  • 相关阅读:
    如何写好 5000 行的 SQL 代码
    Oracle面对“数据倾斜列使用绑定变量”场景的解决方案
    OAuth2.0最简向导(多图预警)
    再见,2019!你好,2020!
    快过年了,来,来,来!给七大姑八大姨好好解释解释【啥是DBA 】
    linux 定期清除日志
    人工智能:才赢李世石,再“战”巴菲特
    人工智能:才赢李世石,再“战”巴菲特
    人工智能:才赢李世石,再“战”巴菲特
    人工智能:才赢李世石,再“战”巴菲特
  • 原文地址:https://www.cnblogs.com/shawk/p/14369628.html
Copyright © 2011-2022 走看看