zoukankan      html  css  js  c++  java
  • 1017考试总结

    1017考试总结

    T1

    ​ 题目大意:

    ​ 一个长度为n的非负整数序列x,满足m个条件:第i个条件为(x[li] or x[li+1]or...or x[ri]=pi)。他想知道是否存在一个序列满足条件,如果存在,他还要构造出一个这样的序列。如果存在这样的序列x,第一行输出Yes,第二行输出n个不超过2^30-1的非负整数表示x[1]~x[n],否则输出一行No。对于100%的数据,n,m≤100,000,1 ≤ li ≤ ri ≤ n,0 ≤ pi < 2 ^ 30。

    ​ 二进制。

    ​ 我们考虑在二进制上一位一位的搞。对于一个条件([l_i, r_i] p_i),假设(p_i)(k)位上为0,那么这个区间里所有数的第(k)位上都是0,我们把(f[l_i ...r_i][k] ++)。如果说(f[i][j] > 0),这说明(x[i])这个数第(j)位上一定为0,我们让(num[i][j] = 0),如果(f[i][j] == 0),那么(num[i][j] = 1)

    ​ 这样每个数就都可以表示出来了。

    ​ 那怎么判断无解呢?用(sum[i][j])表示前(i)个数第(j)位上1的个数,对于每一个条件([l_i, r_i] p_i),判断(sum[r_i][j] - sum[l_i - 1][j])(p_i)的第(j)位是否匹配就好了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e5 + 5;
    int n, m, tag;
    int f[N][31], sum[N][31], num[N][31];
    struct line { int l, r, p; } a[N];
    
    void calc_f(int l, int r, int p) {
        for(int i = 0;i <= 30; i++) {
            if(!((p >> i) & 1)) f[l][i] ++, f[r + 1][i] --; 
        }
    }
    
    int judge(int l, int r, int p) {
        for(int i = 0;i <= 30; i++) {
            int tmp = sum[r][i] - sum[l - 1][i];
            if((!((p >> i) & 1) && tmp > 0) || (((p >> i) & 1) && tmp == 0)) return 0; 
        }
        return 1;
    }
    
    int calc_num(int x) {
        int res = 0;
        for(int i = 0;i <= 30; i++) {
            if(num[x][i] == 1) res += (1 << i);
        }
        return res;
    }
    
    int main() {
    
        n = read(); m = read();
        for(int i = 1;i <= m; i++) {
            a[i].l = read(), a[i].r = read(), a[i].p = read();
            calc_f(a[i].l, a[i].r, a[i].p);
        }
        for(int i = 0;i <= 30; i++) 
            for(int j = 1;j <= n; j++) f[j][i] += f[j - 1][i];
        for(int i = 0;i <= 30; i++) 
            for(int j = 1;j <= n; j++) {
                if(f[j][i] > 0) num[j][i] = 0;
                else num[j][i] = 1;
            }
        for(int i = 0;i <= 30; i++) 
            for(int j = 1;j <= n; j++) 
                sum[j][i] = sum[j - 1][i] + num[j][i];
        for(int i = 1;i <= m; i++) 
            if(!judge(a[i].l, a[i].r, a[i].p)) { tag = 1; break; }
        if(tag) printf("No
    ");
        else {
            printf("Yes
    ");
            for(int i = 1;i <= n; i++) printf("%d ", calc_num(i));
        }
        
        return 0;
    }
    

    T2

    ​ 题目大意:

    ​ 两个字符串s,t,其中s只包含小写字母以及(*),t只包含小写字母。可以进行任意多次操作,每次选择s中的一个(*),将它修改为任意多个(可以是0个)它的前一个字符。他想知道是否能将s修改为t。如果能将s修改为t,输出Yes,否则输出No。对于100%的数据,T≤100,|s|,|t|≤30000。

    ​ 双指针 + 模拟。

    ​ 用两个指针(t, k)表示当先字符串(s, t)枚举到了那个字符。

    ​ 如果当前枚举到的两个字符不相等,输出No。如果当前枚举到的(s)的字符是(x), (x)的下一个字符是(*),直接跳过,一直跳到连续的最后一个(x),并且统计(x)的个数(num1),同样的字符串(t)也要往后跳,也是跳到连续的最后一个(x),统计(x)的个数(num2)。如果(num1 > num2),输出No,否则往下找,重复这个过程。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int T, n, m;
    char a[30005], b[30005];
    
    int main() {
    
        cin >> T; 
        while(T --> 0) {
            cin >> a >> b;
            n = strlen(a); m = strlen(b);
            int t = 0, k = 0, flag = -1;
            while(t <= n || k <= m) {
                if(a[t] != b[k]) {
                    printf("No
    "); flag = 1; break; 
                } 
                else {
                    int num1 = 0, num2 = 0;
                    if(a[t + 1] == '*') {
                        char ch = a[t];
                        while(t <= n && (a[t + 1] == '*' || a[t + 1] == ch)) {
                            if(a[t + 1] == ch) num1 ++; t++;
                        }
                        while(k <= m && b[k + 1] == ch) k ++, num2 ++;
                        if(num1 > num2) {
                            printf("No
    "); flag = 1; break; 
                        }
                    }
                }
                t ++; k ++;
            }
            if(flag == -1) printf("Yes
    ");
        }
        
        return 0;
    }
    

    T3

    ​ 题目大意:

    ​ 一个3×n的数组,要在每一列选一个数(或者不选),满足以下条件:

    ​ (1)如果在第一行选,那它必须大于等于上一个数

    ​ (2)如果在第二行选,那么必须小于等于上一个数

    ​ (3)如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)。

    ​ 对于100%的数据, n <= 100000, m <= 1000000000

    洛谷链接

    数据结构优化DP。

    ​ 我们先设4种状态:1:选第一行的数;2:选第二行的数;3:选第三行的数并且单调不降;4:选第三行的数并且单调不升。

    (dp[i][j])表示第(j)列状态为(i)的最大合法长度:那么状态转移方程是:(dp[i][j] = max(dp[i'][k] + 1))

    (k < i),对于(i = 1, 2)时,(i' = 1, 2, 3, 4)都可以;对于(i = 3)时,(i' = 1, 2, 3);对于(i = 4)时,(i' = 1, 2, 4)

    ​ 暴力枚举(k)(O(n ^ 2))的,用线段树维护最大值则可以优化到(O(n log n))

    #include <bits/stdc++.h>
    
    #define ls(o) (o << 1)
    #define rs(o) (o << 1 | 1)
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e5 + 5;
    int n, cnt, ans;
    int a[N], b[N], c[N], disc[N << 2];
    int dp[5][N], t[5][N << 4];
    
    void insert(int o, int l, int r, int x, int val, int id) {
        if(l == r) { t[id][o] = max(t[id][o], val); return ; }
        if(x <= mid) insert(ls(o), l, mid, x, val, id);
        if(x > mid) insert(rs(o), mid + 1, r, x, val, id);
        t[id][o] = max(t[id][ls(o)], t[id][rs(o)]);
    }
    
    int query(int o, int l, int r, int x, int y, int id) {
        if(x <= l && y >= r) { return t[id][o]; }
        int res = 0;
        if(x <= mid) res = max(res, query(ls(o), l, mid, x, y, id));    
        if(y > mid) res = max(res, query(rs(o), mid + 1, r, x, y, id));
        return res;
    }
    
    int main() {
    
        n = read();
        for(int i = 1;i <= n; i++) a[i] = read(), disc[++ cnt] = a[i];
        for(int i = 1;i <= n; i++) b[i] = read(), disc[++ cnt] = b[i];
        for(int i = 1;i <= n; i++) c[i] = read(), disc[++ cnt] = c[i];
        sort(disc + 1, disc + 1 + cnt);
        cnt = unique(disc + 1, disc + cnt + 1) - disc - 1;
        for(int i = 1;i <= n; i++) a[i] = lower_bound(disc + 1, disc + cnt + 1, a[i]) - disc;
        for(int i = 1;i <= n; i++) b[i] = lower_bound(disc + 1, disc + cnt + 1, b[i]) - disc;
        for(int i = 1;i <= n; i++) c[i] = lower_bound(disc + 1, disc + cnt + 1, c[i]) - disc;
        for(int i = 1;i <= n; i++) {
            dp[1][i] = max(dp[1][i], query(1, 1, cnt, 1, a[i], 1));
            dp[1][i] = max(dp[1][i], query(1, 1, cnt, 1, a[i], 2));
            dp[1][i] = max(dp[1][i], query(1, 1, cnt, 1, a[i], 3));
            dp[1][i] = max(dp[1][i], query(1, 1, cnt, 1, a[i], 4));
            dp[1][i] ++;
            dp[2][i] = max(dp[2][i], query(1, 1, cnt, b[i], cnt, 1));
            dp[2][i] = max(dp[2][i], query(1, 1, cnt, b[i], cnt, 2));
            dp[2][i] = max(dp[2][i], query(1, 1, cnt, b[i], cnt, 3));
            dp[2][i] = max(dp[2][i], query(1, 1, cnt, b[i], cnt, 4));
            dp[2][i] ++;
            dp[3][i] = max(dp[3][i], query(1, 1, cnt, 1, c[i], 1));
            dp[3][i] = max(dp[3][i], query(1, 1, cnt, 1, c[i], 2));
            dp[3][i] = max(dp[3][i], query(1, 1, cnt, 1, c[i], 3));
            dp[3][i] ++;
            dp[4][i] = max(dp[4][i], query(1, 1, cnt, c[i], cnt, 1));
            dp[4][i] = max(dp[4][i], query(1, 1, cnt, c[i], cnt, 2));
            dp[4][i] = max(dp[4][i], query(1, 1, cnt, c[i], cnt, 4));
            dp[4][i] ++;
            insert(1, 1, cnt, a[i], dp[1][i], 1); insert(1, 1, cnt, b[i], dp[2][i], 2);
            insert(1, 1, cnt, c[i], dp[3][i], 3); insert(1, 1, cnt, c[i], dp[4][i], 4);
        }
        for(int i = 1;i <= n; i++) 
            for(int j = 1;j <= 4; j++) 
                ans = max(ans, dp[j][i]);
        printf("%d", ans);
    
        return 0;
    }
    
  • 相关阅读:
    kafka原理
    互斥和条件变量区别
    多线程-----Thread类与Runnable接口的区别
    String、StringBilder和StringBuffer之间的区别
    react native与原生的交互
    Typescript 常见写法
    react项目中的注意点
    js中的正则表达式
    前端总结(一)
    前端性能的优化
  • 原文地址:https://www.cnblogs.com/czhui666/p/13832587.html
Copyright © 2011-2022 走看看