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

    我好菜啊

    A 翻转硬币

    题目大意 : 给定每次可以翻的长度,有m种,问最后把这些硬币翻到指定状态的最少次数

    • 原题。翻转一段区间复杂度太大,如果用差分的话就只需要改变 l 和 r+1 处的值

    • 先把需要的状态转换为差分数组,翻转一段区间就会把两端的值(l和r+1)改掉,如果两端都是0的话没必要改,只有有1的时候才需要改

    • 把差分数组中为1的提出来,可以BFS预处理出来将两个点改掉需要的最小步数,进行DP

    • 把这些点的状态压为 s, 1表示还没消除,f[s]表示从全集到当前状态所需的最小步数,每次转移挑一个点和其它点匹配进行消除,最后f[0]即为答案

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int N = 1e4 + 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;
    }
    
    int n, k, m, a[105], p[25], tot, d[N], c[25][25], q[N], l, r, f[1<<20|5];
    bool b[N];
    
    int main() {
        n = read() + 1; k = read(); m = read();
        for (int i = 1; i <= k; ++i) {
            int x = read();
            b[x] ^= 1; b[x+1] ^= 1;
        }
        for (int i = 1; i <= m; ++i)
            a[i] = read();
        for (int i = 1; i <= n; ++i)
            if (b[i]) p[++tot] = i;
        for (int i = 1; i <= tot; ++i) {
            memset(d, 0x3f, n * 4 + 4);
            d[p[i]] = 0; q[l=r=1] = p[i];
            while (l <= r) {
                int x = q[l++];
                for (int j = 1, y; j <= m; ++j) {
                    if ((y = x + a[j]) <= n && d[y] > 1e9) 
                        d[y] = d[x] + 1, q[++r] = y;
                    if ((y = x - a[j]) >= 1 && d[y] > 1e9) 
                        d[y] = d[x] + 1, q[++r] = y;
                }
            }
            for (int j = 1; j <= tot; ++j)
                c[i][j] = d[p[j]];
        }
        int s = (1 << tot) - 1;
        memset(f, 0x3f, s * 4);
        for (; s >= 1; --s) {
            int j;
            for (j = 1; !((s >> j - 1) & 1); ++j);
            for (int i = j + 1; i <= tot; ++i) {
                if (!((s >> i - 1) & 1)) continue;
                int t = s ^ ((1 << i - 1) + (1 << j - 1));
                f[t] = std::min(f[t], f[s] + c[i][j]);
            }
        }
        printf("%d
    ", f[0] > 1e9 ? -1 : f[0]);
        return 0;
    }
    

    B 一起自习的日子 (Unaccepted)

    题目大意 :

    • 咕咕咕

    Code

    Show Code

    C Sanrd

    题目大意 : 求一个排列的一个LIS 和 LDS,满足找出的两个子序列没有交集

    • 首先要知道一个排列的任意一个 LIS 和 LDS 最多只会有一个地方重合

    • 求出s[i]表示经过位置 i 的 lds 的数量,注意这个方案数会非常大,所以要对一个大质数取模

    • 然后找Lis,要满足经过的点的 s 的和不能等于 LDS 的总数 sum

    • 用树状数组维护

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int N = 5e5 + 5, M = 1e9 + 7;
    
    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;
    }
    
    int n, a[N], lis, lds, len1[N], len2[N], stk[N], tp, g[N];
    int num1[N], num2[N], sum, s[N];
    bool v[N];
    
    struct Node1 {
        int m, num;
        Node1() { m = num = 0; }
    }t1[N];
    
    void Add1(int x, int w, int num) {
        for (; x <= n; x += x & -x) {
            if (w > t1[x].m) t1[x].m = w, t1[x].num= num;
            else if (w == t1[x].m && (t1[x].num += num) >= M) t1[x].num -= M; 
        }
    }
    
    Node1 Ask1(int x) {
        Node1 ans; ans.num = 1;
        for (; x; x -= x & -x) {
            if (t1[x].m > ans.m) ans = t1[x];
            else if (t1[x].m == ans.m && (ans.num += t1[x].num) >= M) ans.num -= M;
        }
        return ans;
    }
    
    struct Node2 {
        int m, p1, p2, n1, n2;
        Node2() {m = p1 = p2 = 0; n1 = n2 = -1;}
    }t2[N], f[N];
    
    void operator += (Node2 &a, const Node2 &b) {
        if (b.m > a.m) a = b;
        if (b.m == a.m && a.n2 == -1) {
            if (b.n1 != a.n1) a.n2 = b.n1, a.p2 = b.p1;
            else if (b.n2 != -1 && b.n2 != a.n1) a.n2 = b.n2, a.p2 = b.p2;
        }
    }
    
    void Add2(int x, int k, Node2 w) {
        w.p1 = w.p2 = k;
        for (; x <= n; x += x & -x) t2[x] += w;
    }
    
    Node2 Ask2(int x) {
        Node2 ans;
        for (; x; x -= x & -x) ans += t2[x];
        return ans;
    }
    
    void Add3(int x, int w, int k) {
        for (; x <= n; x += x & -x)
            if (w > t1[x].m) t1[x].m = w, t1[x].num = k;
    }
    
    Node1 Ask3(int x) {
        Node1 ans;
        for (; x; x -= x & -x)
            if (t1[x].m > ans.m) ans = t1[x];
        return ans;
    }
    
    int main() {
        n = read();
        for (int i = 1; i <= n; ++i)
            a[i] = read();
        for (int i = 1; i <= n; ++i) {//LIS
            int x = Ask1(a[i]).m + 1; Add1(a[i], x, 0);
            lis = std::max(lis, x);
        }
        memset(t1 + 1, 0, sizeof(Node1) * n);
        for (int i = 1; i <= n; ++i) {//LDS ending with i
            Node1 x = Ask1(n - a[i] + 1); x.m++;
            Add1(n - a[i] + 1, len1[i] = x.m, num1[i] = x.num);
            lds = std::max(lds, len1[i]);
        }
        memset(t1 + 1, 0, sizeof(Node1) * n);
        for (int i = n; i >= 1; --i) {//LDS starting with i
            Node1 x = Ask1(a[i]); x.m++;
            Add1(a[i], len2[i] = x.m, num2[i] = x.num);
        }
        for (int i = 1; i <= n; ++i) {
            if (len1[i] + len2[i] == lds + 1) s[i] = 1ll * num1[i] * num2[i] % M;
            if (len1[i] == lds && (sum += num1[i]) >= M) sum -= M; 
        }
        for (int i = 1; i <= n; ++i) {//find the lis that meets the condition
            Node2 &x = f[i] = Ask2(a[i]); x.m++;
            if (x.n1 == -1) x.n1 = s[i];
            else if ((x.n1 += s[i]) >= M) x.n1 -= M;
            if (x.n2 != -1 && (x.n2 += s[i]) >= M) x.n2 -= M;
            Add2(a[i], i, x);
            if (x.m == lis && (x.n1 != sum || (x.n2 != -1 && x.n2 != sum))) {
                int p = i;
                while (p) {
                    int last = stk[++tp] = p; v[p] = 1;
                    p = sum != f[p].n1 ? f[p].p1 : f[p].p2;
                    if ((sum -= s[last]) < 0) sum += M;
                }
                printf("%d
    ", lis);
                while (tp) printf("%d ", stk[tp--]);
                memset(t1 + 1, 0, sizeof(Node1) * n);
                for (i = n; i >= 1; --i) {
                    if (v[i]) continue;
                    Node1 y = Ask3(a[i]); y.m++;
                    g[i] = y.num;
                    Add3(a[i], y.m, i);
                    if (y.m == lds) {
                        printf("
    %d
    ", lds);
                        for (int q = i; q; q = g[q])
                            printf("%d ", q);
                        return 0;
                    }
                }
            }
        }
        puts("-1");
        return 0;
    }
    
  • 相关阅读:
    基于Canvas的时钟
    注意A链接的默认行为
    基于Aptana3+Django开发blog的示例
    使用vbscript替换excel文件的内容
    使用Ajax建立的Server Push和Iframe建立的Comet
    ajax和它的超时
    通用SQL分页程序
    简简单单学习ASP.NET之三
    功能很强大的UI封装类
    封装的一些实现图片水印与图片自动结合缩放的类
  • 原文地址:https://www.cnblogs.com/shawk/p/14368073.html
Copyright © 2011-2022 走看看