【解题报告】Educational Codeforces Round 14

来源:互联网 发布:matlab 矩阵求导 编辑:程序博客网 时间:2024/06/04 08:18

题目链接


A. Fashion in Berland(Codeforces 691A)

思路

根据题意,只需要检查输入的序列中0的个数是否为1即可。另外需要特判夹克上只有一颗扣子的情况。

代码

#include <bits/stdc++.h>using namespace std;int n, a, cnt;int main() {    scanf("%d", &n);    for(int i = 0; i < n; i++) {        scanf("%d", &a);        cnt += a;    }    if(n == 1) {        puts(cnt == 1 ? "YES" : "NO");    }    else {        puts(cnt == n - 1 ? "YES" : "NO");    }    return 0;}

B. s-palindrome(Codeforces 691B)

思路

先建立一个映射表,将所有英文字母映射到与其具有对称结构的英文字母上,然后将字符串反转,再将其用映射表映射成另一个字符串。判断构造出来的字符串是否与原串相同即可。(下面代码构造映射表的方式太麻烦,用两个字符串来表示映射关系会更好)

#include <bits/stdc++.h>using namespace std;bool ok;string s, t;map <int, int> m;void init() {    for(int i = 'A'; i <= 'z'; i++) {        m[i] = '#';    }    m['A'] = 'A'; m['H'] = 'H'; m['I'] = 'I';    m['M'] = 'M'; m['O'] = 'O'; m['T'] = 'T';    m['U'] = 'U'; m['V'] = 'V'; m['W'] = 'W';    m['X'] = 'X'; m['Y'] = 'Y'; m['b'] = 'd';    m['d'] = 'b'; m['o'] = 'o'; m['p'] = 'q';     m['q'] = 'p'; m['v'] = 'v'; m['w'] = 'w';     m['x'] = 'x';}int main() {    init();    cin >> s;    t = s;    reverse(t.begin(), t.end());    ok = true;    for(int i = 0; i < s.size(); i++) {        if(m[t[i]] != s[i]) {            ok = false;        }    }    puts(ok ? "TAK" : "NIE");    return 0;}

C. Exponential notation(Codeforces 691C)

思路

  • 如果输入的是小于 1 的数的话,就从小数点开始往后查找,找到第一个非零的数位,假设这个数位上的数是 x ,根据 x 与小数点的位置可以确定 aEb 中的 b 是多少。最后先后将 x 、小数点和 x 之后的非零数字拼接起来就是 aEb 中的 a
  • 如果输入的是大于或等于 1 的数的话,就从小数点开始向前查找,原理与上一个情况相同。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6 + 5;char str1[maxn];char str2[maxn];int main() {    scanf("%s",str1);    int len_str1 = strlen(str1);    int point = len_str1;    for(int i = 0; i < len_str1; i++) {        if(str1[i]=='.') {            point = i;            break;        }    }    int flag_point;    int len_str2;    for(int i=0; i<len_str1; i++) {        if(str1[i]>'0'&&str1[i]<='9') {            str2[0]=str1[i];            str2[1]='.';            flag_point=i+1;            len_str2=1;            for(int j=i+1; j<len_str1; j++)                if(str1[j]>='0'&&str1[j]<='9')                    str2[++len_str2]=str1[j];            break;        }    }    for(int i=len_str2; i>=1; i--) {        if(str2[i]=='0'||str2[i]=='.') {            len_str2--;        }        else {            break;        }    }    for(int i=0; i<=len_str2; i++) {        printf("%c",str2[i]);    }    if(point != flag_point) {        point>flag_point?printf("E%d\n",point-flag_point):printf("E%d\n",point-flag_point+1);    }    return 0;}

D. Swaps in Permutation(Codeforces 691D)

思路

当允许两个位置进行交换操作时,这两个位置就发生了联系,而且在思考中我们可以发现这种联系是可交换的,也是可传递的。于是我们就可以用无向图表示这种联系。其中点用来表示位置,边用来表示位置之间的联系。
建图完毕后,图必然由若干个连通分量组成。连通分量的意义是,该分量中的位置上的数可以任意排序。根据题意,我们要让同一个分量中大的数排在前面,小的数排在后面,并且对每个分量做这样的排序。那么在完成排序后,总序列一定是符合条件的。
实现上,连通的信息可以用并查集维护(因为除连通信息外不需要用图的其它信息了),除此之外还需要一个从连通分量映射到该分量中所有点的表。这样就能快速地从连通分量中将数提取出来,排序后再放回。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6 + 10;int n, m, u, v, a[maxn], p[maxn];vector <int> vec, G[maxn];void init() {    for(int i = 1; i <= n; i++) {        p[i] = i;    }}int Find(int x) {    return x == p[x] ? x : p[x] = Find(p[x]);}void Union(int x, int y) {    x = Find(x);    y = Find(y);    if(x == y) {        return;    }    p[x] = y;}int main() {    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i++) {        scanf("%d", &a[i]);    }    init();    while(m--){        scanf("%d%d", &u, &v);        Union(u, v);    }    for(int i = 1; i <= n; i++) {        G[Find(i)].push_back(i);    }    for(int i = 1; i <= n; i++) {        if(G[i].size() == 1) {            continue;        }        vec.clear();        for(int idx : G[i]) {            vec.push_back(a[idx]);        }        sort(vec.begin(), vec.end(), [] (int x, int y) { return x > y; });        for(int j = 0; j < G[i].size(); j++) {            int idx = G[i][j];            a[idx] = vec[j];        }    }    for(int i = 1; i <= n; i++) {        printf("%d ", a[i]);    }    return 0;}

E. Xor-sequences(Codeforces 691E)

思路

本题看上去是个复杂的计数问题,实则不然。对于题中的“异或序列”而言,其中的数字的排列方式是由异或模3这种运算决定的。也就是说数字的排列可以看成某种关系。数字 ab 满足 abmod3=0a 才能排在 b 前面(或者相反)。
用图的观点看待这种关系的话,如果代表 a 的点和代表 b 的点满足前述关系,则它们之间有一条无向边相连。也就是说一个长度为 k 的排列对应了图中的一条长度为 k 的路径。如果我们将图用邻接矩阵表示出来,设该矩阵的 k 次幂为 ans ,则 ans[i][j] 恰好表示从点 i 到点 j 的长度为 k 的路径有多少条(不必太过纠结,当成结论记忆就好)。
于是问题就转化成了求邻接矩阵的 k 次幂。在 k 很大的情况下用矩阵快速幂就可以实现。

代码

#include <bits/stdc++.h>using namespace std;const int mod  = 1e9 + 7;const int maxn = 105;typedef long long ll;template <class T>struct matrix {    int n, m;    T a[maxn][maxn];    matrix(int n = 0, int m = 0): n(n), m(m) {        memset(a, 0, sizeof(a));    }    matrix modMul(matrix &b, T mod) const {        matrix tmp(n, b.m);        for(int i = 0; i < n; i++) {            for(int j = 0; j < b.m; j++) {                for(int k = 0; k < m; k++) {                    T t = a[i][k] * b.a[k][j] % mod;                    tmp.a[i][j] = (tmp.a[i][j] + t) % mod;                }            }        }        return tmp;    }    matrix modPow(T e, T mod) const {        matrix a = *this, tmp(n, n);        for(int i = 0; i < n; i++) {            tmp.a[i][i] = 1;        }        for(; e > 0; e >>= 1) {            if(e & 1) {                tmp = tmp.modMul(a, mod);            }            a = a.modMul(a, mod);        }        return tmp;    }};int n;ll k, sum, a[maxn];int main() {    cin >> n >> k;    if(k == 1) {        cout << n << endl;        return 0;    }    for(int i = 1; i <= n; i++) {        cin >> a[i];    }    matrix <ll> mat(n, n), ans(n, n);    for(int i = 1; i <= n; i++) {        for(int j = 1; j <= n; j++) {            if(bitset<64>(a[i] ^ a[j]).count() % 3 == 0) {                mat.a[i-1][j-1] = 1;            }        }    }    ans = mat.modPow(k - 1, mod);    for(int i = 0; i < n; i++) {        for(int j = 0; j < n; j++) {            sum = (sum + ans.a[i][j]) % mod;        }    }    cout << sum << endl;    return 0;}

F. Couple Cover(Codeforces 691F)

思路

先将问题转化为求比 p 小的数对的个数。先统计每个数的出现次数。再暴力枚举数对中的两个数,因为 p 的最大值是 3e6 ,所以枚举出来的两个数的乘积也不超过 3e6 。将枚举的数的乘积限制一下,枚举的复杂度就降为 O(nlogn) 了。出现 logn 是因为这个式子:

ni=11i=O(log(n))

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxa = 3e6;ll n, a, all, m, q, num[maxa], sum[maxa];int main() {    scanf("%I64d", &n);    all = n * (n - 1);    while(n--) {        scanf("%I64d", &a);        m = max(m, a);        num[a]++;    }    for(ll i = 1; i <= m; i++) {        for(ll j = 1; j <= m; j++) {            if(i * j > maxa) {                break;            }            if(i == j) {                sum[i*i] += num[i] * (num[i] - 1);            }            else {                sum[i*j] += num[i] * num[j];            }        }    }    for(ll i = 2; i <= maxa; i++) {        sum[i] += sum[i-1];    }    scanf("%I64d", &q);    while(q--) {        scanf("%I64d", &a);        printf("%I64d\n", all - sum[a-1]);    }    return 0;}

0 0
原创粉丝点击