zoukankan      html  css  js  c++  java
  • Codeforces Round #501 (Div. 3)

    链接:https://codeforces.com/contest/1015
    A - Points in Segments
    题意:给定n个范围(l_i,r_i),问哪些点没有出现过
    思路:由于(1leq l_i leq r_i leq m)且m的范围很小,模拟即可

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 110;
    
    int n, m, vis[N];
    vector<int> res;
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            int l, r;
            scanf("%d%d", &l, &r);
            for (int k = l; k <= r; k++) vis[k] = 1;
        }
        for (int i = 1; i <= m; i++) {
            if (vis[i]) continue;
            res.push_back(i);
        }
        printf("%d
    ", res.size());
        for (int i = 0; i < res.size(); i++) {
            printf("%d", res[i]);
            printf(i == res.size() - 1 ? "
    " : " ");
        }
        return 0;
    }
    

    B - Obtaining the String
    题意:给定两个字符串,每次可以交换相邻两个字符,给出任意一组交换次数小于(10^4)的方案使得a串成为b串,输出交换的次数与位置,无解输出-1
    思路:从后向前处理b串,每次找到一个位置p使得a[p]=b[i],然后模拟交换的过程

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 60;
    
    int n, c[N];
    char a[N], b[N];
    vector<int> res;
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d%s%s", &n, a + 1, b + 1);
        for (int i = 1; i <= n; i++) c[a[i] - 'a' + 1] += 1;
        for (int i = 1; i <= n; i++) c[b[i] - 'a' + 1] -= 1;
        for (int i = 1; i <= 26; i++) {
            if (0 != c[i]) {
                printf("-1
    ");
                return 0;
            }
        }
        for (int i = n; i >= 1; i--) {
            if (a[i] == b[i]) continue;
            int p = 0;
            for (int k = 1; k <= i - 1; k++)
                if (a[k] == b[i]) p = k;
            for (int k = p; k <= i - 1; k++) {
                res.push_back(k);
                swap(a[k], a[k + 1]);
            }
        }
        printf("%d
    ", res.size());
        for (int i = 0; i < res.size(); i++) {
            printf("%d", res[i]);
            printf(i == res.size() - 1 ? "
    " : " ");
        }
        return 0;
    }
    

    C - Songs Compression
    题意:有m大小的空间,有n个物品,第i个物品本来的大小为(a_i),压缩后的大小为(b_i),问你最少只需要压缩多少个物品,就能把这个n个物品放进m大小的空间
    思路:贪心,对于每个物品,按照(a_i-b_i)从大到小排序,然后找到最前面最少的物品压缩,使得这n个物品放进m大小的空间

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 100010;
    
    struct node {
        ll a, b, d;
    };
    
    int n;
    ll m;
    node nd[N];
    
    bool cmp(node a, node b)
    {
        return a.d > b.d;
    }
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d%lld", &n, &m);
        ll sa = 0, sb = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld", &nd[i].a, &nd[i].b);
            sa += nd[i].a;
            sb += nd[i].b;
            nd[i].d = nd[i].a - nd[i].b;
        }
        if (sb > m) {
            printf("-1
    ");
            return 0;
        }
        sort(nd + 1, nd + n + 1, cmp);
        int res = 0;
        for (int i = 1; i <= n; i++) {
            if (sa <= m) break;
            sa -= nd[i].d;
            res += 1;
        }
        printf("%d
    ", res);
        return 0;
    }
    

    D - Walking Between Houses
    题意:现在有n个房子排成一列,编号为(1~n),起初你在第1个房子里,现在你要进行k次移动,每次移动一都可以从一个房子i移动到另外一个其他的房子j里(i!=j),移动的距离为(mid j-imid)。问你进过k次移动后,移动的总和可以刚好是s,若可以则输出YES并依次输出每次到达的房子的编号,否则输出NO
    思路:由于每次最多移动(n-1)步,最少移动一步,所以当(s<k)或者(s>k*(n-1))时,无解,直接输出NO即可,有解情况下,考虑以下构造方法
    对于每一步,平均每次需要移动(frac{s}{k})步,其中有(s\%k)次需要移动(frac{s}{k}+1)步,所以采用向左走一次、向右走一次的方法即可

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    ll n, k, s;
    vector<ll> res;
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%lld%lld%lld", &n, &k, &s);
        if (s < k || s > k * (n - 1)) {
            printf("NO
    ");
            return 0;
        }
        printf("YES
    ");
        ll b = s / k, bm = s % k, now = 1, t = 1;
        for (ll i = 1; i <= bm; i++) {
            if (1 == now) res.push_back(now + b + 1);
            else res.push_back(now - b - 1);
            now = now + (b + 1) * t;
            t = -t;
        }
        for (ll i = bm + 1; i <= k; i++) {
            if (now + b <= n) {
                res.push_back(now + b);
                now += b;
            }
            else {
                res.push_back(now - b);
                now -= b;
            }
        }
        for (ll i = 1; i <= k; i++) {
            printf("%lld", res[i - 1]);
            printf(i == k ? "
    " : " ");
        }
        return 0;
    }
    

    E - Stars Drawing (Easy Edition)
    见Hard Edition
    F - Stars Drawing (Hard Edition)
    题意:给你一个(n*m)大小的字符矩阵,仅由"."和"*"组成,提问这个图可否划分为一些由"*"组成的十字形状,这些十字之间可以有重叠,如果可以完全覆盖输出每个十字中心坐标与边长度,不可以输出-1
    思路:对于每个"*",我们预处理出他上下左右能延伸的最大范围,对于每个"*",我们就能知道他能够形成以他为中心的十字形状最大为多少,然后差分维护一下哪些点被选过了,如果到最后还有点没有被选到,那就是不可能的,输出-1

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 1010;
    
    struct node {
        int a, b, r;
        node() { }
        node(int _a, int _b, int _r) : a(_a), b(_b), r(_r) { }
    };
    
    int n, m, pre[N][N], af[N][N], up[N][N], down[N][N];
    int bc[N][N], br[N][N];
    char s[N][N];
    vector<node> res;
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
        for (int i = 1; i <= n; i++) {
            int now = 0;
            for (int k = 1; k <= m; k++) {
                if (s[i][k] == '.') pre[i][k] = now = 0;
                else {
                    pre[i][k] = now;
                    if (0 == now) now = k;
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            int now = 0;
            for (int k = m; k >= 1; k--) {
                if (s[i][k] == '.') af[i][k] = now = 0;
                else {
                    af[i][k] = now;
                    if (0 == now) now = k;
                }
            }
        }
        for (int k = 1; k <= m; k++) {
            int now = 0;
            for (int i = 1; i <= n; i++) {
                if (s[i][k] == '.') up[i][k] = now = 0;
                else {
                    up[i][k] = now;
                    if (0 == now) now = i;
                }
            }
        }
        for (int k = 1; k <= m; k++) {
            int now = 0;
            for (int i = n; i >= 1; i--) {
                if (s[i][k] == '.') down[i][k] = now = 0;
                else {
                    down[i][k] = now;
                    if (0 == now) now = i;
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int k = 1; k <= m; k++) {
                if ('.' == s[i][k]) continue;
                int imin = 0;
                if (0 != pre[i][k] && 0 != af[i][k] && 0 != up[i][k] && 0 != down[i][k]) {
                    imin = min(k - pre[i][k], af[i][k] - k);
                    imin = min(imin, i - up[i][k]);
                    imin = min(imin, down[i][k] - i);
                }
                if (0 == imin) continue;
                res.push_back(node(i, k, imin));
                bc[i][k - imin] += 1;
                bc[i][k + imin + 1] -= 1;
                br[i - imin][k] += 1;
                br[i + imin + 1][k] -= 1;
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int k = 1; k <= m; k++) {
                bc[i][k] += bc[i][k - 1];
                br[i][k] += br[i - 1][k];
            }
        }
        int ok = 1;
        for (int i = 1; i <= n; i++) {
            for (int k = 1; k <= m; k++) {
                if ('.' == s[i][k]) continue;
                if (0 == bc[i][k] && 0 == br[i][k]) ok = 0;
            }
        }
        if (0 == ok) {
            printf("-1
    ");
            return 0;
        }
        printf("%d
    ", res.size());
        for (int i = 0; i < res.size(); i++) printf("%d %d %d
    ", res[i].a, res[i].b, res[i].r);
        return 0;
    }
    

    G - Bracket Substring
    题意:给定一个只由左右括号组成的、长度为m的字符串s,问长度为(2*n)的包含s的合法括号序列方案数,答案对1000000007取模,(1leq nleq 100,1leq |s|leq 200)
    思路:字符串下标从1开始,to[i][0/1]表示对于[1,i]这个前缀,在后面加上一个"("或者")"后,这个字符串的后缀与s前缀能够匹配的最大长度为多少,可以暴力处理
    假设dp[i][j][k][p]表示前i个字符,有j个"("还没有被匹配掉,同时这个i个字符的后缀能够与s匹配的最大长度为k,并且是否完全包含s,所以枚举前i个字符的状态,对于第i+1个字符
    如果第i+1个字符为"(",那么这个i+1个字符能够与s匹配的最大长度就会变成to[k][0](相当于[1,k]这个前缀加上"(",即to[k][0]),注意此时to[k][0]可能等于m,那么dp[i+1][j+1][to[k][0]][p|(to[k][0] == m)]需要加上dp[i][j][k][p]
    如果第i+1个字符为")",同样dp[i+1][j-1][to[k][1]][p|(to[k][1] == m)]需要加上dp[i][j][k][p]
    最后的答案就是(sum_{i=0}^{m} dp[2*n][0][i][1])

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 210;
    const int mod = 1000000007;
    
    int dp[N][N][N][2], to[N][2], n, m, cnt;
    char a[N], b[N];
    
    bool check(int la, int lb, int len)
    {
        for (int i = 0; i < len; i++)
            if (a[la + i] != b[lb + i]) return false;
        return true;
    }
    
    int calc(char *b, int len)
    {
        for (int i = len; i >= 1; i--)
            if (check(1, len - i + 1, i)) return i;
        return 0;
    }
    
    int main()
    {
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%d%s", &n, a + 1);
        m = strlen(a + 1);
        if (a[1] == '(') to[0][0] = 1;
        else to[0][1] = 1;
        for (int i = 1; i <= m; i++) {
            b[++cnt] = a[i];
            b[++cnt] = '(';
            to[i][0] = calc(b, cnt);
            b[cnt] = ')';
            to[i][1] = calc(b, cnt);
            cnt -= 1;
        }
        dp[0][0][0][0] = 1;
        for (int i = 0; i <= 2 * n - 1; i++) {
            for (int j = 0; j <= n; j++) {
                for (int k = 0; k <= m; k++) {
                    for (int p = 0; p <= 1; p++) {
                        if (j + 1 <= n) {
                            int &now = dp[i + 1][j + 1][to[k][0]][p | (to[k][0] == m)];
                            now = (now + dp[i][j][k][p]) % mod;
                        }
                        if (j >= 1) {
                            int &now = dp[i + 1][j - 1][to[k][1]][p | (to[k][1] == m)];
                            now = (now + dp[i][j][k][p]) % mod;
                        }
                    }
                }
            }
        }
        int res = 0;
        for (int i = 0; i <= m; i++) res = (res + dp[2 * n][0][i][1]) % mod;
        printf("%d
    ", res);
        return 0;
    }
    
  • 相关阅读:
    一个FLAG #03# 蛇形填数
    一个FLAG #02# 逆序输出
    一个FLAG #01# 重学C/C++以及算法
    MAVLink笔记 #01# 维基百科翻(译)
    编译原理 #04# 中缀表达式转化为四元式(JavaScript实现)
    Java开发:手机电话号码校验
    解决java poi循环遍历行getLastRowNum出现不准确的问题
    Redis的安装和简单测试
    JS解析xml字符串,并把xml展示在HTML页面上
    解决cxf+springmvc发布的webservice,缺少types,portType和message标签的问题
  • 原文地址:https://www.cnblogs.com/chd-acm/p/13618639.html
Copyright © 2011-2022 走看看