zoukankan      html  css  js  c++  java
  • 【题录】Atcoder ARC#104

    C.Fair Elevator

    每一站都必须要有人上车/下车,则如果把上车标记为1,下车标记为2,最后的合法序列一定是形如x个1,x个2这样的若干个段拼在一起的。所以我们暴力枚举分段点及段的长度判断是否有合法解。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1000000
    int n, a[maxn], b[maxn], r[maxn], rec[maxn];
    bool mark[maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) {
            a[i] = read(), b[i] = read();
            if(a[i] != -1 && b[i] != -1 && a[i] >= b[i]) { printf("No
    "); return 0; } 
            if(a[i] != -1) {
                if(r[a[i]]) { printf("No
    "); return 0; } 
                r[a[i]] = 1; rec[a[i]] = i;
            }
            if(b[i] != -1) {
                if(r[b[i]]) { printf("No
    "); return 0; }
                r[b[i]] = 2; rec[b[i]] = i;
            }
        }
        mark[1] = 1;
        for(int i = 1; i <= 2 * n; i ++) {
            if(!mark[i]) continue;
            for(int L = 1; L <= n; L ++) {
                if(i + 2 * L - 1 > 2 * n) break;
                bool flag = 1;
                for(int j = i; j < i + L; j ++) {
                    if(r[j] == 2) { flag = 0; break; }
                    if(r[j + L] == 1) { flag = 0; break; }
                    if(r[j] && rec[j + L] && (rec[j + L] != rec[j])) { 
                        flag = 0; break; 
                    }
                }
                if(flag) mark[i + 2 * L] = 1;
            }
        }
        if(mark[2 * n + 1]) printf("Yes
    ");
        else printf("No
    ");
        return 0;
    }

    D.Multiset Mean

    如果最后的平均值是x,则序列中(sum (a_{i} - x) = 0),将元素分为大于x的和小于x的两部分,即为(sum (a_{i} - x) = sum(x - b_{i}))。小于x的取值情况:1到x-1,每种物品最多拿K个,大于x的取值情况:1到n-x,每种物品最多拿K个。由此我们预处理dp[i][j]表示价值为1-i的物品每个最多拿K个的情况下总价值为j的方案数。这里使用无限背包转多重背包即为(O(nm))的复杂度。然后对每一个x统计方案数得到答案。

    #include <bits/stdc++.h>
    using namespace std;
    #define N 105
    #define maxn 600005
    int n, K, mod, cnt, num[N], dp[N][maxn];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void Up(int &x, int y) {
        x += y; if(x >= mod) x -= mod;
    }
    
    int add(int x, int y) {
        x += y; if(x >= mod) x -= mod; return x;
    }
    int sub(int x, int y) {
        x -= y; if(x < 0) x += mod; return x;
    }
    int mul(int x, int y) {
        return 1ll * x * y % mod;
    }
    
    int main() {
        n = read(), K = read(), mod = read();
        int lim = (K * n * (n - 1)) >> 1;
        dp[0][0] = 1; 
        for(int i = 1; i <= n; i ++) {
            for(int j = 0; j <= lim; j ++) dp[i][j] = dp[i - 1][j]; 
            for(int j = i; j <= lim; j ++)
                Up(dp[i][j], dp[i][j - i]);
            for(int j = lim; j >= 0; j --) 
                if(j >= (K + 1) * i) 
                    dp[i][j] = sub(dp[i][j], dp[i][j - (K + 1) * i]);
        }
        for(int i = 1; i <= n; i ++) {
            int ans = 0;
            for(int j = 0; j <= lim; j ++)
                Up(ans, mul(dp[i - 1][j], dp[n - i][j]));
            ans = mul(ans, (K + 1));
            ans = sub(ans, 1);
            printf("%d
    ", ans);
        }
        return 0;
    }

    E.Random LIS

    爆搜每个位置上面数字的排名,此时最长上上子序列的长度一定。问题转化为满足(x_{n} < x_{n + 1}) 且 (x_{n} <= A_{n}) 的数列有多少个。把(A_{n}) 从小到大分成一段一段的,不同段之间相对大小一定满足,方案相乘,同段之中则实用组合数求解。虽然C(n, m) 中的n很大,但因为m很小,所以可以O(m) 计算。

    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000
    #define INF 1000000009
    #define mod 1000000007
    int n, len, ans = 0, mx, cnt, a[N], b[N], p[N], cal[N];
    int A[N], inv[N], dp[N], lim[N], R[N], t, mark[N];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    int mul(int x, int y) {
        return 1ll * x * y % mod;
    }
    
    int add(int x, int y) {
        x += y; if(x >= mod) x -= mod;
        return x;
    }
    
    void Up(int &x, int y) {
        x += y; if(x >= mod) x -= mod;
    }
    
    int Qpow(int x, int t) {
        int base = 1; 
        for(; t; t >>= 1, x = mul(x, x))
            if(t & 1) base = mul(base, x);
        return base;
    }
    
    int C(int n, int m) {
        if(n < m) return 0;
        int num = 1;
        for(int i = 1; i <= m; i ++) 
            num = mul(num, mul(n - i + 1, inv[i]));
        return num; 
    }
    
    void dfs2(int now, int lst) {
        if(now == (mx + 1)) {
            int ans1 = 1;
            for(int i = 1; i <= cnt; i ++) cal[i] = 0;
            for(int i = 1; i <= mx; i ++) cal[b[i]] ++;
            for(int i = 1; i <= cnt; i ++) 
                ans1 = mul(ans1, C(p[i], cal[i]));
            ans1 = mul(ans1, len);
            Up(ans, ans1);
            return;
        }
        for(int i = lst; i <= cnt; i ++) {
            if(lim[now] < R[i]) break;
            b[now] = i;
            dfs2(now + 1, i);
        }
    }
    
    void Work() {
        cnt = 0; len = 0;
        for(int i = 1; i <= n; i ++) dp[i] = 0;
        for(int i = 1; i <= n; i ++)
            for(int j = 0; j < i; j ++)
                if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
        for(int i = 1; i <= n; i ++) len = max(len, dp[i]);
        for(int i = 1; i <= mx; i ++) lim[i] = INF;
        for(int i = 1; i <= n; i ++)
            lim[a[i]] = min(lim[a[i]], A[i]);
        for(int i = 1; i <= mx; i ++)
            for(int j = i + 1; j <= mx; j ++)
                lim[i] = min(lim[i], lim[j]);
        for(int i = 1; i <= mx; i ++) 
            if(lim[i] - lim[i - 1]) p[++ cnt] = lim[i] - lim[i - 1], R[cnt] = lim[i];
        dfs2(1, 1);
    }
    
    void dfs(int num) {
        if(num == (n + 1)) {
            for(int i = 1; i <= mx; i ++) 
                if(!mark[i]) return;
            Work();
            return;
        }
        for(int i = 1; i <= n; i ++) {
            a[num] = i; int rec = mx; mx = max(mx, i);
            mark[i] ++;
            dfs(num + 1);
            mx = rec; mark[i] --;
        }
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) inv[i] = Qpow(i, mod - 2);
        dfs(1);
        for(int i = 1; i <= n; i ++) 
            ans = mul(ans, Qpow(A[i], mod - 2));
        printf("%d
    ", ans);
        return 0;
    }

    F.Visibility Sequence

    如果把一个点同它左侧高度大于自己的点之间连一条边(不存在则连向超级源点)那么将会构成一棵树。观察这棵树的性质,会发现每一个子树节点的编号都是一个连续的区间[l, r],且根节点的编号为l,其权值为子树中最大。考虑当前的一个根节点下面的若干个儿子,则编号大的点的权值一定大于等于编号小的点的权值。若每个点的权值都在约束范围之内,则满足以上几个条件的每一棵不同形态(点的编号不同)的树都是一个不同的p序列。为了尽量让每个点的权值在范围内,可以贪心的让每个点的权值往大了取减少对下方点的限制。设dp[l][r][num]为子树(不包括当前根)的节点编号为[l,r],当前根的权值为num+1 的不同方案数。枚举的时候就枚举儿子中编号最大的点进行转移。

    #include <bits/stdc++.h>
    using namespace std;
    #define N 105
    #define mod 1000000007
    int n, a[N], dp[N][N][N];
    
    int read() {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    int mul(int x, int y) {
        return 1ll * x * y % mod;
    }
    
    void Up(int &x, int y) {
        x += y; if(x >= mod) x -= mod;
    }
    
    int dfs(int l, int r, int mx) {
        if(l > r) return 1;
        if(!mx) return 0;
        if(dp[l][r][mx] != -1) return dp[l][r][mx];
        dp[l][r][mx] = 0; 
        for(int i = l; i <= r; i ++) {
            int top = min(mx, a[i]);
            Up(dp[l][r][mx], mul(dfs(l, i - 1, top), dfs(i + 1, r, top - 1))); 
        }
        return dp[l][r][mx];
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) a[i] = read();
        for(int i = 1; i <= n; i ++)
            for(int j = i; j <= n; j ++)
                for(int k = 1; k <= n; k ++)
                    dp[i][j][k] = -1;
        printf("%d
    ", dfs(1, n, n));
        return 0;
    }
  • 相关阅读:
    webRTC中语音降噪模块ANS细节详解(四)
    基于MCRAOMLSA的语音降噪(三):实现(续)
    基于MCRAOMLSA的语音降噪(一):原理
    VoIP语音处理流程和知识点梳理
    linux I/O内存访问
    十六、输入子系统驱动模型
    十三、【ADC】ADC读取S5p6818电源值
    put_user()和get_user()用户空间传递数据
    十四、【watchdog】看门狗
    十七、内核中的锁机制
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/13777825.html
Copyright © 2011-2022 走看看