题目戳这里
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; }
其实等价于这样写
#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; }
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; }
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; }
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; }
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; }