1. 程式人生 > >Hello 2019 Solution

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 = true
; 14 } 15 return flag; 16 } 17 18 int main() 19 { 20 while (scanf("%s", s) != EOF) puts(solve() ? "YES" : "NO"); 21 return 0; 22 }
View Code

 

 

B. Petr and a Combination Lock

二進位制列舉

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int
n, 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 }
View Code

 

 

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$

思路: