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;
    }
    
  • 相关阅读:
    2020暑假项目-车辆派遣管理系统需求
    2020暑假项目-车辆派遣管理系统
    关于页面刷新或者调用方法事获取不到元素信息或者出现缺少对象错误的换位思考setTimeout的使用
    JSON 传值 textarea中虚拟换行功能
    我的MYSQL学习心得(十) 自定义存储过程和函数
    我的MYSQL学习心得(九) 索引
    我的MYSQL学习心得(八) 插入 更新 删除
    我的MYSQL学习心得(六) 函数
    我的MYSQL学习心得(七) 查询
    我的MYSQL学习心得(四) 数据类型
  • 原文地址:https://www.cnblogs.com/shawk/p/14369628.html
Copyright © 2011-2022 走看看