Hello 2019 Solution
A. Gennady and a Card Game
簽到.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 char s[5], t[5]; 5 6 bool solve() 7 { 8 int flag = false; 9 for (int i = 1; i <= 5; ++i) 10 { 11 scanf("%s", t); 12 if (t[0] == s[0] || t[1] == s[1]) 13 flag = trueView Code; 14 } 15 return flag; 16 } 17 18 int main() 19 { 20 while (scanf("%s", s) != EOF) puts(solve() ? "YES" : "NO"); 21 return 0; 22 }
B. Petr and a Combination Lock
二進位制列舉
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 intView Coden, a[20]; 5 bool solve() 6 { 7 for (int i = 0; i < (1 << n); ++i) 8 { 9 int res = 0; 10 for (int j = 1; j <= n; ++j) 11 { 12 int vis = (i >> (j - 1)) & 1; 13 res += a[j] * (vis ? 1 : -1); 14 } 15 if (res % 360== 0) return true; 16 } 17 return false; 18 } 19 20 int main() 21 { 22 while (scanf("%d", &n) != EOF) 23 { 24 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 25 puts(solve() ? "YES" : "NO"); 26 } 27 return 0; 28 }
C. Yuhao and a Parenthesis
Solved.
題意:
給出n個括號序列,求兩兩匹配成合法序列的最多對數
思路:
考慮單個括號序列最後一定可以化簡成 ))) 或者 ((( 或者)))(((這三種形式
或者本身就是合法的
發現第三種)))(((不可能和別人兩兩匹配成合法序列
只需考慮))) 和 ((( 的配對以及本身就是合法序列的配對即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 500010 5 int n; 6 int l[N], r[N], good; 7 char s[N]; 8 9 int main() 10 { 11 while (scanf("%d", &n) != EOF) 12 { 13 memset(l, 0, sizeof l); 14 memset(r, 0, sizeof r); 15 good = 0; 16 for (int i = 1; i <= n; ++i) 17 { 18 scanf("%s", s + 1); 19 int len = strlen(s + 1); 20 int left = 0, right = 0; 21 for (int i = 1; i <= len; ++i) 22 { 23 if (s[i] == '(') ++left; 24 else 25 { 26 if (left > 0) --left; 27 else ++right; 28 } 29 } 30 if (left > 0 && right > 0) continue; 31 if (left == 0 && right == 0) ++good; 32 else if (left == 0) ++r[right]; 33 else ++l[left]; 34 } 35 int res = 0; 36 for (int i = 1; i <= 500000; ++i) res += min(l[i], r[i]); 37 res += good / 2; 38 printf("%d\n", res); 39 } 40 return 0; 41 }View Code
D. Makoto and a Blackboard
Upsolved.
題意:
$剛開始黑板上有一個n,我們假定此時在黑板上的數是v$
那麼每次可以取$v的一個因數去替換這個數,求最後留下的數的期望$
思路:
我們假定$n一共有p個因數,以及dp[x][j] 表示進行n為x,並且進行j輪的期望$
易得轉移方程
$dp[x][j] = \frac{\sum_{i = 1}^{i = p} dp[y][j - 1]}{p}$
那麼很顯然的一個遞推就出來了,每次列舉n的每個因子,再列舉n的每個因子的每個因子,遞推上去
T了,喵喵喵,(覺得個數會很少?
後來發現我們要求的只是 $dp[n][k]$
而且後面那部分的轉移其實是可以拆的,拆成若干個因子期望的和/個數 再乘起來
那麼我們質因子相同的放在一起做
這樣就有字首和性質
假設$n = x_1^{p_1} \cdot x_2 ^ {p_2} \cdots$
複雜度就是$O(p * k)$ 因為p不會太大
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 10010 6 #define pli pair <ll, int> 7 const ll MOD = (ll)1e9 + 7; 8 ll n; int k; 9 ll inv[N]; 10 11 vector <pli> getfact(ll n) 12 { 13 vector <pli> res; 14 for (ll i = 2; i * i <= n; ++i) 15 { 16 int need = 0; 17 while (n % i == 0) 18 { 19 ++need; 20 n /= i; 21 } 22 if (need) res.emplace_back(i, need); 23 } 24 if (n != 1) res.emplace_back(n, 1); 25 return res; 26 } 27 28 ll f(ll x, ll p) 29 { 30 vector <ll> dp(p + 1, 0); 31 dp[0] = 1; 32 for (int i = 1; i <= p; ++i) 33 dp[i] = (dp[i - 1] * x) % MOD; 34 for (int rep = 0; rep < k; ++rep) 35 { 36 for (int i = 1; i <= p; ++i) dp[i] = (dp[i - 1] + dp[i]) % MOD; 37 for (int i = 1; i <= p; ++i) dp[i] = (dp[i] * inv[i + 1]) % MOD; 38 } 39 return dp[p]; 40 } 41 42 int main() 43 { 44 inv[1] = 1; 45 for (int i = 2; i < N; ++i) inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD; 46 while (scanf("%lld%d", &n, &k) != EOF) 47 { 48 ll ans = 1; 49 for (auto p : getfact(n)) 50 ans = (ans * f(p.first, p.second)) % MOD; 51 printf("%lld\n", ans); 52 } 53 return 0; 54 }View Code
F. Alex and a TV Show
Unsolved.
題意:
$有n個可重集,有四種操作$
$1 \;\;x\;\; v\;\; 表示將第\;x\;個集合設為\;\;{v}$
$2 \;\;x \;\;y\;\; z\;\; 表示將\;y\;和\;z\;兩個集合並起來 賦給 \;\;x$
$3 \;\;x \;\;y \;\;z\;\; 表示將\;\;y\;\;和 \;\;z\;\;兩個集合求乘積,乘積的定義為\;\; {gcd(a, b | a \in A, \; b \in B)} \;\;賦給\;\;x$
$4 \;\; x\;\; v\;\; 表示詢問\;\;v\;\;在\;\;x\;\;中出現的次數 \;\;MOD \;\;2$
思路: