• $ACM$ 期末考试


    (ACM) 期末考试

    (A. Alphabet)

    题意

    给定一个由小写字母组成的字符串 (s),可以在任意位置插入任意数量的小写字母
    计算最少插入多少小写字母,使得新字符串 (s') 中含有子序列 abcdefghijklmnopqrstuvwxyz

    (|s| < 50)

    题解

    即求字符串中的最长上升子序列

    定义 (dp[i]) 为到 (i) 位置所具备的最长上升子序列,则 (dp[i] = maxleft{dp[j] + 1, j < i ight})

    (O(n^2)) 暴力转移

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    char str[107];
    int dp[107];
    int main()
    {
        scanf("%s", str + 1);
        int L = strlen(str + 1);
        for(int i = 1; i <= L; ++i){
            dp[i] = 1;
            for(int j = 1; j < i; ++j)
                if(str[j] < str[i]) dp[i] = max(dp[i], dp[j] + 1);
        }
        int ans = 0;
        //for(int i = 1; i <= L; ++i) cout << i << ' ' << dp[i] <<endl;
        for(int i = 1; i <= L; ++i) ans = max(ans, dp[i]);
        printf("%d
    ", 26 - ans);
        return 0;
    }
    

    (B. Barbells)

    题意

    (n) 个杠铃和 (m) 个杠铃片,(n, mleq 14)

    在满足杠铃两端重量一致的前提下,计算这些器件一共可以组和出多少种不同的重量

    题解

    双重二进制枚举杠铃片的选则,(check) 重量是否一致,用与运算判断是否为独立集合即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int n, m;
    LL a[20], b[20];
    set<LL> st;
    int main()
    {
        n = read(), m = read();
        for(int i = 0; i < n; ++i) scanf("%lld", &a[i]);
        for(int i = 0; i < m; ++i) scanf("%lld", &b[i]);
        for(int i = 0; i < (1 << m); ++i) {
            for(int j = 0; j < (1 << m); ++j) {
                if((i & j) == 0) {
                    LL x = 0, y = 0;
                    for(int k = 0; k < m; ++k) {
                        if(i & (1 << k)) x += b[k];
                        if(j & (1 << k)) y += b[k];
                    }
                    if(x == y) st.insert(x + y);
                }
            }
        }
        set<LL> ans;
        for(auto i: st) {
            for(int j = 0; j < n; ++j)
                ans.insert(i + a[j]);
        }
        for(auto i: ans) cout << i << endl;
        return 0;
    }
    

    (C, Buggy Robot)

    题意

    在一个 (n imes m) 的二维迷宫上,给一个机器人输入一串 URDL 的指令 (s, |s| leq 50),操纵其从入口走到出口

    机器人按照指令移动

    • 若当前指令使得机器人遇到障碍物 # 或者走出边界,那么机器人会忽视当前指令
    • 若走到终点,剩下的所有指令作废

    已知指令错误,现在允许在任意位置插入新指令,也允许删除任意指令,亦可以不改变指令

    计算最小的修改次数,使得机器人可以走到终点

    (n, m, |s|leq 50)

    题解

    定义 (dp[i][j][k]) 为执行第 (k) 条指令后,机器人走到 ((i, j)) 位置时所需要修改的最小次数

    考虑状态转移

    • 若删除当前指令,则 (dp[i][j][k + 1] = min(dp[i][j][k + 1], dp[i][j][k] + 1))
    • 若在当前位置增添指令,则 (dp[i'][j'][k] = min(dp[i'][j'][k], dp[i][j][k] + 1))
    • 若什么也不做,则 (dp[i'][j'][k + 1] = min(dp[i'][j'][k + 1], dp[i][j][k]))

    (bfs) 暴力转移

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = (1 << 20) + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int n, m, mp[10];
    char g[100][100], str[100];
    int dp[100][100][100];
    struct node
    {
        int x, y, pos;
        node() {}
        node(int _x, int _y, int _pos) {x = _x, y = _y, pos = _pos;}
    };
    bool check(int x, int y) {return x >= 1 && x <= n && y >= 1 && y <= m && g[x][y] != '#';}
    void bfs(int sx, int sy, int ex, int ey, int L)
    {
        queue<node> q;
        dp[sx][sy][0] = 0;
        q.push(node(sx, sy, 0));
        while(!q.empty()) {
            node temp = q.front(); q.pop();
            for(int i = 1; i <= 4; ++i) {
                int tx = temp.x + DX[i], ty = temp.y + DY[i];
                if(check(tx, ty) && dp[tx][ty][temp.pos] > dp[temp.x][temp.y][temp.pos] + 1) {
                        dp[tx][ty][temp.pos] = dp[temp.x][temp.y][temp.pos] + 1;
                        q.push(node(tx, ty, temp.pos));
                    }
            }
            if(temp.pos < L) {
                if(dp[temp.x][temp.y][temp.pos + 1] > dp[temp.x][temp.y][temp.pos] + 1) {
                    dp[temp.x][temp.y][temp.pos + 1] = dp[temp.x][temp.y][temp.pos] + 1;
                    q.push(node(temp.x, temp.y, temp.pos + 1));
                }
                int tpos = temp.pos + 1;
                int tx = temp.x + DX[mp[str[tpos]]], ty = temp.y + DY[mp[str[tpos]]];
                if(!check(tx, ty)) tx = temp.x, ty = temp.y;
                if(dp[tx][ty][tpos] > dp[temp.x][temp.y][temp.pos]) {
                    dp[tx][ty][tpos] = dp[temp.x][temp.y][temp.pos];
                    q.push(node(tx, ty, tpos));
                }
            }
        }
    }
    int main()
    {
        int sx, sy, ex, ey;
        mp['U'] = 1, mp['R'] = 2, mp['D'] = 3, mp['L'] = 4;
        scanf("%d %d", &n, &m);
        memset(dp, inf, sizeof(dp));
        for(int i = 1; i <= n; ++i)
            scanf("%s", g[i] + 1);
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                if(g[i][j] == 'R') sx = i, sy = j;
                if(g[i][j] == 'E') ex = i, ey = j;
            }
        }
        scanf("%s", str + 1);
        int L = strlen(str + 1);
        bfs(sx, sy, ex, ey, L);
        int ans = inf;
        for(int i = 1; i <= L; ++i) ans = min(ans, dp[ex][ey][i]);
        printf("%d
    ", ans);
        return 0;
    }
    

    后记

    感觉这题相当难想,也相当难写,需要仔细体会

    (D. Cameras)

    题意

    (n) 个房子,其中 (k) 个房子有灯

    现在要求每 (r) 个连续房子至少得有两个房子有灯,计算需要增加的灯的个数

    (nleq 100000, 0leq kleq n)

    题解

    贪心,优先往右边的房子放灯

    嵌套循环寻找右边第一个没有灯的位置,该位置灯的数量加一,注意这个嵌套循环最多循环三次,复杂度最多带个常数 (3)

    要求快速查询区间内灯的个数,以及单点修改,所以考虑用树状数组进行维护

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int n, k, r, a[N];
    //BIT
    int c[N];
    int lowbit(int x) {return x & (-x);}
    void upd(int *c, int i, int val)
    {
        while(i <= n){
            c[i] += val;
            i += lowbit(i);
        }
    }
    int query(int *c, int i)
    {
        int ans = 0;
        while(i > 0) {
            ans += c[i];
            i -= lowbit(i);
        }
        return ans;
    }
    int main()
    {
        n = read(), k = read(), r = read();
        for(int i = 1; i <= k; ++i) {
            int x = read();
            a[x] = 1;
            upd(c, x, 1);
        }
        int ans = 0;
        for(int i = 1; i <= n - r + 1; ++i) {
            int num = query(c, i + r - 1) - query(c, i - 1);
            if(num < 2) {
                int t = 0;
                for(int j = i + r - 1; j >= i; --j) {
                    if(!a[j]) upd(c, j, 1), t++;
                    if(t == 2 - num) break;
                }
                ans += 2 - num;
            }
        }
        cout << ans << endl;
        return 0;
    }
    

    (E. Contest Score)

    题意

    设某次 (xcpc) 共有 (n) 个题目,现给定一个队伍对于每道题的解题时间 (t_{i}),以及竞赛策略

    • (1.) 先读前 (k) 个题
    • (2.) 选择花费时间最少的题目进行解答
    • (3.) 如果还有题目剩余,读下一个题目
    • (4.) 如果还有没做完的题目,回到 (2)

    假设读题不花费时间,输出罚时

    (1leq kleq nleq 300, 1leq t_{i}leq 1000000)

    题解

    签到,优先队列模拟即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int n, k;
    LL t[500];
    priority_queue<LL, vector<LL>, greater<LL> > pq;
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> k;
        LL time = 0, ans = 0;
        int cnt = k + 1;
        for(int i = 1; i <= n; ++i) cin >> t[i];
        for(int i = 1; i <= k; ++i) pq.push(t[i]);
        while(!pq.empty()) {
            time += pq.top(); ans += time; pq.pop();
            if(cnt <= n) pq.push(t[cnt++]);
        }
        cout << ans << endl;
        return 0;
    }
    

    (F. Equality)

    题意

    给定 (a + b = c),判断等式是否成立

    题解

    签到,格式化读入之后判断即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int main()
    {
        int a, b, c;
        scanf("%d + %d = %d", &a, &b, &c);
        puts(a + b == c ? "YES" : "NO");
        return 0;
    }
    

    (G. Gravity)

    题意

    给定一个 (n imes m) 的二维格点图,模拟苹果受重力的掉落情况

    (1leq n, mleq 50)

    题解

    签到,模拟即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int n, m;
    char g[100][100];
    int main()
    {
        cin >> n >> m;
        for(int i = 1; i <= n; ++i)
            scanf("%s", g[i] + 1);
        for(int j = 1; j <= m; ++j) {
            for(int i = n; i >= 1; --i) {
                if(g[i][j] == 'o') {
                    g[i][j] = '.';
                    int f = 0;
                    for(int k = i; k <= n; ++k)
                        if(g[k][j] == 'o' || g[k][j] == '#') {g[k - 1][j] = 'o'; f = 1; break;}
                    if(!f) g[n][j] = 'o';
                }
            }
        }
        for(int i = 1; i <= n; ++i)
            printf("%s
    ", g[i] + 1);
        return 0;
    }
    

    (H. Islands)

    题意

    给定一个 (n imes m) 的二维格点图,(L) 表示陆地,(W) 表示海洋,(C) 表示云朵,云朵既可以变成海洋也可以变成陆地

    恰当地变换 (C) 的形态,计算图中最少有多少陆地连通块

    (1leq n, mleq 50)

    题解

    把所有与 (L) 相连通的 (C) 全部变成 (L),因为这样连通块个数才不会增加

    (dfs) 即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int n, m, vis[100][100];
    char g[100][100];
    bool check(int x, int y) {return x >= 1 && x <= n && y >= 1 && y <= m;}
    void dfs(int x, int y)
    {
        vis[x][y] = 1;
        for(int i = 1; i <= 4; ++i) {
            int tx = x + DX[i], ty = y + DY[i];
            if(!vis[tx][ty] && check(tx, ty) && g[tx][ty] != 'W') dfs(tx, ty);
        }
    }
    int main()
    {
        //ios::sync_with_stdio(false);
        cin >> n >> m;
        int ans = 0;
        for(int i = 1; i <= n; ++i)
            scanf("%s", g[i] + 1);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= m; ++j)
                if(!vis[i][j] && g[i][j] == 'L') ans++, dfs(i, j);
        cout << ans << endl;
        return 0;
    }
    

    后记

    血的教训,开启 ios::sync_with_stdio(false); 语句之后,不能使用 (scanf, printf),否则会出错

    (I. Mismatched Socks)

    (J. Postman)

    题意

    一维数轴上分布了 (n) 个点,对应的坐标为 (x_{i}),所需要的邮件数量为 (m_{i})

    邮递员每次从 (x = 0) 处出发,携带 (k) 个邮件,来回送货

    请计算邮递员送完所有点需要的信所走的最短路

    (1leq nleq 1000, 1leq k, |x_{i}|, m_{i}leq 10000000)

    题解

    贪心,正负点分开送,每次优先送最远的点,模拟即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e3 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    LL n, k;
    struct data
    {
        LL a, b;
        data() {}
        data(LL _a, LL _b) {a = _a, b = _b;}
        bool operator < (const data &x) const {return a < x.a;}
    }d1[N], d2[N];
     
    LL getAns(data *d, int nn)
    {
        LL ans = 0;
        for(int i = nn; i >= 1; --i) {
            LL dis = 2LL * d[i].a;
            LL num = d[i].b;
            ans += (num / k) * dis;
            if(num % k) {
                ans += dis;
                LL left = k - (num % k);
                for(int j = i - 1; j >= 1; --j) {
                    if(d[j].b >= left) {d[j].b -= left; break;}
                    else left -= d[j].b, d[j].b = 0;
                }
            }
        }
        return ans;
    }
    int main()
    {
        scanf("%lld %lld", &n, &k);
        int n1 = 0, n2 = 0;
        for(int i = 1; i <= n; ++i) {
            LL x, y;
            scanf("%lld %lld", &x, &y);
            if(x >= 0) d1[++n1] = data(x, y);
            else d2[++n2] = data(-x, y);
        }
        sort(d1 + 1, d1 + 1 + n1);
        sort(d2 + 1, d2 + 1 + n2);
        LL ans1 = getAns(d1, n1);
        LL ans2 = getAns(d2, n2);
        cout << ans1 + ans2 << endl;
        return 0;
    }
    /*
    7 1
    9400000 10000000
    9500000 10000000
    9600000 10000000
    9700000 10000000
    9800000 10000000
    9900000 10000000
    10000000 10000000
    */
    

    (K. Six Sides)

    题意

    俩人掷俩六面骰子

    • 若第一个人的点数大,那么第一个人获胜
    • 若平局,继续抛
    • 若第一个人的点数小,那么第一个人输、

    计算第一个人赢的数学期望

    题解

    (a) 为玩家 (1) 点数大于玩家 (2) 点数的实验数

    (b) 为玩家 (1) 点数小于玩家 (2) 点数的实验数

    (a = b = 0),则 (E = 0),否则 (E = frac{a}{a + b})

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int a[10], b[10];
    int main()
    {
        for(int i = 1; i <= 6; ++i) cin >> a[i];
        for(int i = 1; i <= 6; ++i) cin >> b[i];
        int cnt1 = 0, cnt2 = 0;
        for(int i = 1; i <= 6; ++i) {
            for(int j = 1; j <= 6; ++j) {
                if(a[i] > b[j]) cnt1++;
                else if(a[i] < b[j]) cnt2++;
            }
        }
        if(cnt1 == cnt2 && !cnt1) puts("0.00000");
        else printf("%.5f
    ", double(cnt1) / double(cnt1 + cnt2));
        return 0;
    }
    

    (L. Three Square)

    题意

    给定 (3) 个长宽确定的长方形,判断是否可以组成一个正方形

    题解

    三个长方形中的最长边一定是正方形的边长,以此为依据分类讨论

    一共 (6 imes(4 + 4) = 48) 种情况

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int a[10], b[10];
     
    bool check1(int a1, int b1, int a2, int b2, int a3, int b3)
    {
        //cout << a1 << ' ' << b1 << ' ' << a2 << ' ' << b2 << ' ' << a3 << ' ' << b3 << endl;
        return (a1 == a2 + a3 && b2 == b3 && a1 == b1 + b3 || a1 == a2 && a1 == a3 && a1 == b1 + b2 + b3);
    }
    int main()
    {
        int maxx = 0;
        for(int i = 1; i <= 3; ++i) cin >> a[i] >> b[i], maxx = max(maxx, max(a[i], b[i]));
        int f1 = 0, f2 = 0;
        if(a[1] == maxx) {
            f1 = check1(a[1], b[1], a[2], b[2], a[3], b[3]); f2 |= f1;
            f1 = check1(a[1], b[1], a[2], b[2], b[3], a[3]); f2 |= f1;
            f1 = check1(a[1], b[1], b[2], a[2], a[3], b[3]); f2 |= f1;
            f1 = check1(a[1], b[1], b[2], a[2], b[3], a[3]); f2 |= f1;
        }
        if(b[1] == maxx) {
            f1 = check1(b[1], a[1], a[2], b[2], a[3], b[3]); f2 |= f1;
            f1 = check1(b[1], a[1], a[2], b[2], b[3], a[3]); f2 |= f1;
            f1 = check1(b[1], a[1], b[2], a[2], a[3], b[3]); f2 |= f1;
            f1 = check1(b[1], a[1], b[2], a[2], b[3], a[3]); f2 |= f1;
        }
        if(a[2] == maxx) {
            f1 = check1(a[2], b[2], a[1], b[1], a[3], b[3]); f2 |= f1;
            f1 = check1(a[2], b[2], a[1], b[1], b[3], a[3]); f2 |= f1;
            f1 = check1(a[2], b[2], b[1], a[1], a[3], b[3]); f2 |= f1;
            f1 = check1(a[2], b[2], b[1], a[1], b[3], a[3]); f2 |= f1;
        }
        if(b[2] == maxx) {
            f1 = check1(b[2], a[2], a[1], b[1], a[3], b[3]); f2 |= f1;
            f1 = check1(b[2], a[2], a[1], b[1], b[3], a[3]); f2 |= f1;
            f1 = check1(b[2], a[2], b[1], a[1], a[3], b[3]); f2 |= f1;
            f1 = check1(b[2], a[2], b[1], a[1], b[3], a[3]); f2 |= f1;
        }
        if(a[3] == maxx) {
            f1 = check1(a[3], b[3], a[2], b[2], a[1], b[1]); f2 |= f1;
            f1 = check1(a[3], b[3], a[2], b[2], b[1], a[1]); f2 |= f1;
            f1 = check1(a[3], b[3], b[2], a[2], a[1], b[1]); f2 |= f1;
            f1 = check1(a[3], b[3], b[2], a[2], b[1], a[1]); f2 |= f1;
        }
        if(b[3] == maxx) {
            f1 = check1(b[3], a[3], a[2], b[2], a[1], b[1]); f2 |= f1;
            f1 = check1(b[3], a[3], a[2], b[2], b[1], a[1]); f2 |= f1;
            f1 = check1(b[3], a[3], b[2], a[2], a[1], b[1]); f2 |= f1;
            f1 = check1(b[3], a[3], b[2], a[2], b[1], a[1]); f2 |= f1;
        }
        puts(f2 ? "YES" : "NO");
        return 0;
    }
    /*
    2 6
    2 6
    2 6
    */
    

    (M. Zigzag)

    题意

    给定一个长度为 (50) 的序列,计算其中最长的 (zigzagging) 子序列

    (zigzagging) 子序列定义为:递增递减交错的序列

    例如:(1, 3, 2, 6, 5)

    (nleq 50)

    题解

    类似于最长上升子序列

    定义 (dp1[i]) 表示到第 (i) 位置为止,且第 (i) 位置为增长趋势的 (zigzagging subsequences) 的最长长度

    定义 (dp2[i]) 表示到第 (i) 位置为止,且第 (i) 位置为下降趋势的 (zigzagging subsequences) 的最长长度

    考虑状态转移

    [dp1[i] = maxleft{dp1[i], dp2[j] + 1, j < i ight} ]

    [dp2[i] = maxleft{dp2[i], dp1[j] + 1, j < i ight} ]

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    int n, a[100], dp1[100], dp2[100];
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n;
        for(int i = 1; i <= n; ++i) cin >> a[i];
        int ans = 0;
        for(int i = 1; i <= n; ++i){
            dp1[i] = dp2[i] = 1;
            for(int j = 1; j < i; ++j) {
                if(a[j] > a[i]) dp1[i] = max(dp1[i], dp2[j] + 1);
                if(a[j] < a[i]) dp2[i] = max(dp2[i], dp1[j] + 1);
            }
        }
        for(int i = 1; i <= n; ++i) ans = max(ans, max(dp1[i], dp2[i]));
        cout << ans << endl;
        return 0;
    }
    

    (N. Paint)

    题意

    给定长为 (n) 的序列,以及 (k) 个子区间 ([a_{i}, b_{i}])

    选取若干个不相交的子区间,使得未被覆盖的元素个数最少

    (1leq nleq 10^{18}, 1leq kleq 200000)

    题解

    (k) 个区间按照右端点升序排序,左端点降序/升序排序

    定义 (dp1[i]) 表示,以第 (i) 个区间为终点区间,所得到的最少的未被覆盖的元素个数

    定义 (dp2[i] = maxleft{dp1[j], j < i ight})

    考虑状态转移,二分查找最后一个区间 (j),使得 (b_{j} < a_{i})

    (dp1[i] = max(dp1[i], dp2[j] + a_{i} - b_{i} + 1])

    更新 (dp2[i] = max(dp2[i - 1], dp1[i]))

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 2e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    LL n;
    int k;
    LL dp1[N], dp2[N];
    struct node
    {
        LL L, R;
        node() {}
        node(LL _L, LL _R) {L = _L, R = _R;}
    }d[N];
    bool cmp(node x, node y)
    {
        if(x.R == y.R) return x.L > y.L;
        return x.R < y.R;
    }
    int main()
    {
        scanf("%lld %d", &n, &k);
        for(int i = 1; i <= k; ++i) {
            LL x, y;
            scanf("%lld %lld", &x, &y);
            d[i] = node(x, y);
        }
        sort(d + 1, d + 1 + k, cmp);
        for(int i = 1; i <= k; ++i) {
            int p = lower_bound(d + 1, d + 1 + k, node(INF, d[i].L), cmp) - 1 - d;
            dp1[i] = d[i].R - d[i].L + 1 + dp2[p];
            dp2[i] = max(dp2[i - 1], dp1[i]);
        }
        //for(int i = 1; i <= k; ++i)
            //cout << d[i].L << ' ' << d[i].R << ' ' << dp1[i] << ' ' << dp2[i] << endl;
        LL ans = INF;
        for(int i = 1; i <= k; ++i) ans = min(ans, n - dp1[i]);
        cout << ans << endl;
        return 0;
    }
    /*
    15 5
    1 4
    5 6
    6 8
    8 12
    12 15
    */
    

    后记

    在结构体数组里面用 lower_bound 需要使用第四个参数,自定义 cmp 比较函数,这是一个新姿势

    (O. Shopping)

    题意

    (n) 个货物,每个货物有无限多个,价格为 (a_{i})

    (q) 个客户,每人有 (v_{i}) 的资金,他们从 (l_{i}) 逛到 (r_{i}),对于每一种货物,他们都会买到买不起为止

    请计算每人剩余的资金

    (1leq n, qleq 200000, 1leq a_{i}, v_{i}leq 10^{18}, 1leq l_{i}, r_{i}leq n)

    思路

    记当前在 (pos) 位置,资金还剩余 (x)

    问题等价于在 ([pos, r_{i}]) 内寻找第一个不大于 (x) 的位置

    由于是无序序列,考虑用线段树求解,复杂度套个 (log_{2}{n})

    由于取模操作,每次购买物品资金至少减少一半,所以最多购买 (log_{2}v_{i}) 件物品

    总的复杂度为 (O(qlognlogv_{i}))

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL MOD = 11092019;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int N = 2e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
     
    LL n, q, a[N];
    struct node
    {
        LL l, r, minn;
    }t[N * 4];
    void pushup(int rt)
    {
        t[rt].minn = min(t[rt * 2].minn, t[rt * 2 + 1].minn);
    }
    void build(int L, int R, int rt){
        t[rt].l = L, t[rt].r = R;
        if(L == R){
            t[rt].minn = a[L];
            return;
        }
        int mid = (L + R) / 2;
        build(L, mid, rt * 2);
        build(mid + 1, R, rt * 2 + 1);
        pushup(rt);
    }
    int query(int L, int R, LL val, int rt)
    {
        //cout << L << ' ' << R << endl;
        if(t[rt].l == t[rt].r){
            if(t[rt].minn <= val) return t[rt].l;
            else return -1;
        }
        int mid = (t[rt].l + t[rt].r) / 2;
        int ans = -1;
        if(L <= mid && t[rt * 2].minn <= val) {
            ans = query(L, R, val, rt * 2);
            if(ans == -1){
                if(mid < R && t[rt * 2].minn <= val) ans = query(L, R, val, rt * 2 + 1);
            }
            return ans;
        }
        else if(mid < R && t[rt * 2 + 1].minn <= val) return query(L, R, val, rt * 2 + 1);
        return -1;
    }
    int main()
    {
        scanf("%lld %lld", &n, &q);
        for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        build(1, n, 1);
        while(q--) {
            LL m;
            int L, R;
            scanf("%lld %d %d", &m, &L, &R);
            int p = L;
            while(1) {
                m %= a[p];
                p = query(p + 1, R, m, 1);
                if(p == -1) break;
            }
            cout << m << endl;
        }
        return 0;
    }
    /*
    5 3
    5 3 2 4 6
    107 1 4
    */
    

    后记

    也可以使用单调栈求解,回头再思考一下

    (P. Contest Strategy)

  • 相关阅读:
    每日日报63
    每日日报62
    每日日报61
    每日日报60
    每日日报59
    每日日报58
    el-table表格拖动排序
    vue/eslint
    $attrs $listeners
    table封装成全局组件
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/13180080.html
Copyright © 2020-2023  润新知