Codeforces Round #400 (Div. 1 + Div. 2, combined)——ABCDE

题目戳这里

 

A.A Serial Killer

题目描述似乎很恶心,结合样例和样例解释猜测的题意

使用C++11的auto可以来一手骚操作

#include <bits/stdc++.h>

using namespace std;

int n;

string s[4];

map <string, int> p;

int main() {
    cin >> s[0] >> s[1];
    p[s[0]] = p[s[1]] = 1;
    cin >> n;
    cout << s[0] << " " <<s[1] << endl;
    while(n --) {
        cin >> s[2] >> s[3];
        p[s[2]] ++, p[s[3]] ++;
        for(auto iter : p)
            if(iter.second == 1) cout << iter.first << " ";
        puts("");
    }
    return 0;
}
View Code

其实等价于这样写

#include <bits/stdc++.h>

using namespace std;

int n;

string s[4];

map <string, int> p;

int main() {
    cin >> s[0] >> s[1];
    p[s[0]] = p[s[1]] = 1;
    cin >> n;
    cout << s[0] << " " <<s[1] << endl;
    while(n --) {
        cin >> s[2] >> s[3];
        p[s[2]] ++, p[s[3]] ++;
        for(map <string, int>::iterator iter = p.begin();iter != p.end();iter ++)
            if(iter -> second == 1) cout << iter -> first << " ";
        puts("");
    }
    return 0;
}
View Code

 

B.Sherlock and his girlfriend

很蠢的一题,质数标1,合数标2就好了

#include <bits/stdc++.h>

#define rep(i, j, k) for(int i = j;i <= k;i ++)

#define rev(i, j, k) for(int i = j;i >= k;i --)

using namespace std;

typedef long long ll;

const int maxn = 100010;

int n, a[maxn];

int main() {
    ios::sync_with_stdio(false);
    cin >> n;
    if(n < 3) puts("1");
    else puts("2");
    for(int i = 2;i <= n + 1;i ++)
        if(a[i] != 2) {
            a[i] = 1;
            for(int j = i << 1;j <= n + 1;j += i)
                a[j] = 2;
        }
    for(int i = 2;i <= n + 1;i ++)
        printf("%d ", a[i]);
    return 0;
}
View Code

 

C.Molly's Chemicals

有那么一点意思的题目

求有多少段连续子段和为k的非负power

 

显然k为2的话,大概能2^0 - 2^50左右吧

所以直接枚举 k^p 即可

偷懒套个map,复杂度O(n(logn)^2)

 

注意:

1.非负power,包括1

2. |k| = 1 特判,否则死循环

#include <bits/stdc++.h>

#define rep(i, j, k) for(int i = j;i <= k;i ++)

#define rev(i, j, k) for(int i = j;i >= k;i --)

using namespace std;

typedef long long ll;

int n, t;

ll k, s[100010];

map <ll, int> p;

int main() {
    ios::sync_with_stdio(false);
    int x;
    cin >> n >> t;
    rep(i, 1, n) cin >> x, s[i] = s[i - 1] + x;
    for(ll j = 1;abs(j) <= 100000000000000ll;j *= t) {
        p.clear(), p[0] = 1;
        rep(i, 1, n) {
            k += p[s[i] - j];
            p[s[i]] ++;
        }
        if(t == 1 || (t == -1 && j == -1)) break;
    }
    cout << k;
    return 0;
}
View Code

 

D.The Door Problem

应该注意到each door is controlled by exactly two switches

所以显然对于一开始锁上的门,只能选择一个开关

一开始打开的门,可以选择都不选或者都选

于是我们可以想到2-sat来解决

实际上2-sat也的确可以解决

 

但是我们注意到这个2-sat的特殊性

每组中的两个选择在某种程度上是等价的

而我们平时做的 Ai 与 Ai’ 是不等价的

两个选择等价意味着连的边已经是无向边

即若有Ai -> Aj,则必有Aj -> Ai

这样就不需要再tarjan

直接并查集就可以解决了

#include <cstdio>

const int maxn = 100010;

int n, m, f[maxn << 1], a[2][maxn];

bool op[maxn];

int find_(int x) {
    if(f[x] != x) return f[x] = find_(f[x]);
    return x; 
}

void union_(int x, int y) {
    x = find_(x), y = find_(y);
    if(x != y) f[x] = y;
}

int main() {
    scanf("%d %d", &n, &m);
    for(int i = 1;i <= n;i ++) scanf("%d", &op[i]);
    for(int k, j, i = 1;i <= m;i ++) {
        scanf("%d", &j);
        while(j --) {
            scanf("%d", &k);
            if(a[0][k]) a[1][k] = i;
            else a[0][k] = i;
        }
    }
    for(int i = m << 1;i;i --) f[i] = i;
    for(int i = 1;i <= n;i ++)
        if(op[i]) union_(a[0][i], a[1][i]), union_(a[0][i] + m, a[1][i] + m);
        else      union_(a[0][i], a[1][i] + m), union_(a[0][i] + m, a[1][i]);
    for(int i = 1;i <= m;i ++)
        if(find_(i) == find_(i + m)) {
            puts("NO");
            return 0;
        }
    puts("YES");
    return 0;    
}
View Code

 

E.The Holmes Children

手动计算发现 f 函数为欧拉函数

gcd(x, y) = 1

x + y = n

=> gcd(x, x + y) = 1 即 gcd(x, n) = 1 

g(n) = n ,剩下部分很好解决

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int mod_ = 1e9 + 7;

ll f(ll x) {
    ll ret = x;
    for(ll i = 2;i * i <= x;i ++)
        if(x % i == 0) {
            ret /= i, ret *= (i - 1);
            while(x % i == 0) x /= i;
        }
    if(x != 1) ret /= x, ret *= (x - 1);
    return ret;
}

int main(){
    ll n, k;
    cin >> n >> k;
    k = (k + 1) >> 1;
    for(int i = 1;i <= k;i ++) {
        n = f(n);
        if(n == 1) break;
    }
    cout << n % mod_; 
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/ytytzzz/p/6836564.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值