• 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
    ", 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
    ", 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$

    思路:

     对每一个可重集维护$f[i]表示i的倍数出现的次数的奇偶性,用bitset维护$

    那么

    对于1操作,我们只需要根号暴力就可以了

    对于2操作,本来是相加,但是只关心奇偶性的话就是半加就好,即异或

    对于3操作,本来是相乘,对应的位运算就是与

    对于4操作,反演一下

    我们令$F[n] 表示n倍数的出现次数$

    那么有$F[n] = sumlimits_{n | d} f[d]$

    反演之后便是

    $f[n] = sumlimits_{n | d}  mu(frac{d}{n}) cdot F[d]$

    这里的莫比乌斯函数1和-1没有区别,我们只关心奇偶性

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 100010
     5 #define M 7010
     6 #define D 7000
     7 int n, q, mu[M];
     8 bitset <M> a[M], b[M], s[N];
     9 
    10 int main()
    11 {
    12     for (int i = 1; i <= D; ++i) mu[i] = 1;
    13     for (int i = 2; i <= D; ++i) for (int j = i * i; j <= D; j += i * i) mu[j] = 0;
    14     for (int i = 1; i <= D; ++i) for (int j = i; j <= D; j += i)
    15     {
    16         a[j][i] = 1;
    17         if (mu[j / i]) b[i][j] = 1;
    18     }        
    19     while (scanf("%d%d", &n, &q) != EOF)
    20     {
    21         for (int i = 1; i <= n; ++i) s[i].reset();
    22         for (int i = 1, op, x, y, z, v; i <= q; ++i)
    23         {
    24             scanf("%d%d", &op, &x);
    25             if (op == 1 || op == 4)
    26             {
    27                 scanf("%d", &v);
    28                 if (op == 1) s[x] = a[v];
    29                 else putchar(((s[x] & b[v]).count() & 1) + '0');
    30             }
    31             else
    32             {
    33                 scanf("%d%d", &y, &z);
    34                 if (op == 2) s[x] = s[y] ^ s[z];
    35                 else s[x] = s[y] & s[z]; 
    36             }
    37         }
    38         putchar('
    ');
    39     }    
    40     return 0;
    41 }
    View Code
  • 相关阅读:
    APIO2019游记
    ZJOI2019赛季回顾
    「HNOI 2019」白兔之舞
    LOJ #6539 奇妙数论题
    BZOJ4314 倍数?倍数!
    伯努利数学习笔记&&Luogu P3711 仓鼠的数学题
    BZOJ 5093[Lydsy1711月赛]图的价值 线性做法
    AtCoder Grand Contest 030题解
    Codeforces Round #542 (Div. 1) 题解
    Codeforces Round #541 (Div. 2)题解
  • 原文地址:https://www.cnblogs.com/Dup4/p/10223350.html
Copyright © 2020-2023  润新知