Codeforces Round #455 (Div. 2)

C. Python Indentation

分析

\(dp[i][j]\) 表示到第 \(i\) 行时,缩进次数为 \(j\) 的方案数。

code

#include<bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
string c;
long long dp[5555][5555];
int main() {
    int n;
    cin >> n;
    dp[0][0] = 1;
    for (int i = 0; i < n; i++) {
        cin >> c;
        if(c == "f") {
            for (int j = 1; j < n; j++) {
                dp[i + 1][j] = dp[i][j - 1];
            }
        } else {
            for (int j = n; j >= 0; j--) {
                dp[i + 1][j] = (dp[i][j] + dp[i + 1][j + 1]) % MOD;
            }
        }
    }
    cout << dp[n][0] << endl; 
    return 0;
}

D. Colorful Points

分析

将字符串按字符分组,记录字符和连续相同的字符个数,那么每次删掉的字符应该是,左右两边的组中的一个字符,中间每组两个字符 ,将空组删掉,合并可以合并的组。模拟一下就行了,因为对于每组每回合至少会删掉一个字符,复杂度 \(O(n)\)

code

#include<bits/stdc++.h>
using namespace std;
string s;
vector<pair<char, int> > v, tmp;
int main() {
    cin >> s;
    int len = s.length();
    v.push_back(pair<int, int>(s[0], 1));
    for (int i = 1; i < len; i++) {
        if(s[i] == v.back().first) {
            v[v.size() - 1].second++;
        } else {
            v.push_back(pair<int, int>(s[i], 1));
        }
    }
    int ans = 0;
    while(v.size() > 1) {
        ans++;
        for (int i = 0; i < v.size(); i++) {
            if(!i) {
                if(v[i].second - 1 > 0) {
                    v[i].second--;
                    tmp.push_back(v[i]);
                }
            } else if(i == v.size() - 1) {
                if(v[i].second - 1 > 0) {
                    v[i].second--;
                    if(!tmp.empty() && tmp.back().first == v[i].first) {
                        tmp[tmp.size() - 1].second += v[i].second;
                    } else {
                        tmp.push_back(v[i]);
                    }
                }
            } else {
                if(v[i].second - 2 > 0) {
                    v[i].second -= 2;
                    if(!tmp.empty() && tmp.back().first == v[i].first) {
                        tmp[tmp.size() - 1].second += v[i].second;
                    } else {
                        tmp.push_back(v[i]);
                    }   
                }
            }
        }
        v = tmp;
        tmp.clear();
    }
    cout << ans << endl;
    return 0;
}

E. Coprocessor

分析

与前面两题相比感觉这道题反而没什么技巧。

找入度为 0 的点,分类存储,遍历再去 DFS 更新其它点的入度,重复这样即可。

code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> G[N];
int c[N], d[N];
vector<int> v0, v1;

void dfs(int flg, int u) {
    for (int v : G[u]) {
        d[v]--;
        if (!d[v]) {
            if (c[v]) {
                if (flg)
                    dfs(flg, v);
                else
                    v1.push_back(v);
            } else {
                if (flg)
                    v0.push_back(v);
                else
                    dfs(flg, v);
            }
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> c[i];
    }
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        G[v].push_back(u);
        d[u]++;
    }
    for (int i = 0; i < n; i++) {
        if (!d[i]) {
            c[i] ? v1.push_back(i) : v0.push_back(i);
        }
    }
    int ans = 0;
    while (!v0.empty() || !v1.empty()) {
        for (int u : v0) {
            dfs(0, u);
        }
        v0.clear();
        if (!v1.empty()) ans++;
        for (int u : v1) {
            dfs(1, u);
        }
        v1.clear();
    }
    cout << ans << endl;
    return 0;
}

F. AND-permutations

分析

构造题。

对二进制和位运算还是不够敏感啊。

对于第一个问题,要求排列后每个数都不在原来的位置,且与位置序号数按位与运算后都为 0 。

对于奇数情况,无解,因为奇数情况下所有数表示成二进制后,末尾为 \(1\) 的数个数一定比为 \(0\) 的多 \(1\) ,所以无论如何,都会存在一个对应情况按位与后末尾为 \(1\)

对于偶数情况,只需要注意到一个事实:

\(n=2^k\)\(m=2^k-1\)\((n+i)\&(m-i)=0(m \geq i)\) ,因为此时 \(n\) 除了前导 \(1\) 全是 \(0\)\(m\) 除了前导 \(0\) 以外全是 \(1\) ,那么可以想象成这些 \(1\) 全都可以加到 \(n\) 上去。

举个例子,若 \(n=12\),我们找到小于等于 \(n\) 的最大的 \(2\) 的倍数 \(8\) ,那么 \((7,8)\ (6,9)\ (5,10)\ (4,11)\ (3,12)\) 对应,然后 \(n=2\),我们找到小于等于 \(n\) 的最大的 \(2\) 的倍数 \(2\)\((1,2)\) 对应,\(n=0\) 后可以发现所有数都有对应关系了。因为起始 \(n\) 是偶数,且每次减去的数一定是偶数,且 \(n\) 一定不会减到小于 \(0\),所以一定能构造出答案。

对于第二个问题,按位运算后都不为 \(0\)

如果 \(n\)\(2\) 的倍数,则无解,因为没有数可以和 \(n\) 对应。

对于 \(n<8\) 的情况要特判。

对于 \(n\geq 8\) 的情况,考虑 \([8,15]\ [16, 31]...\),对于每个区间单独考虑,转化成二进制数后每个数的首位数一定都为 \(1\) ,只要保证每个数都不在原来的位置即可。

code

#include <bits/stdc++.h>
using namespace std;

int p2(int x) {
    int a = 1;
    while (a * 2 <= x) {
        a *= 2;
    }
    return a;
}

int ans[111111];

int main() {
    int n;
    cin >> n;
    if (n & 1) {
        cout << "NO\n";
    } else {
        cout << "YES\n";
        int m = n;
        while (m) {
            int x = p2(m);
            for (int i = x, j = x - 1; i <= m; i++, j--) { ans[i] = j; ans[j] = i; }
            m -= 2 * (m - x + 1);
        }
        for (int i = 1; i <= n; i++) {
            cout << ans[i] << " \n"[i == n];
        }
    }
    if (n <= 5 || p2(n) == n)
        cout << "NO\n";
    else {
        cout << "YES\n";
        if (n == 6)
            cout << "3 6 2 5 1 4\n";
        else if (n == 7)
            cout << "7 3 6 5 1 2 4\n";
        else {
            cout << "7 3 6 5 1 2 4";
            int l = 8;
            while (l <= n) {
                int r = min(n, l * 2 - 1);
                for (int i = l + 1; i <= r; i++) {
                    cout << " " << i;
                }
                cout << " " << l;
                l = r + 1;
            }
            cout << endl;
        }
    }
    return 0;
}
posted @ 2018-01-30 15:19  ftae  阅读(166)  评论(0编辑  收藏  举报