• CodeForces Round #295 Div.2


    A. Pangram

    题意:判断字符串中26种字母是否全都出现过,不区分大小写。

    题本身不难,可是忘了用getchar()吞掉输入第一行最末的换行符,导致被某些别有用心的人在比赛快结束的时候Hack了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 100 + 10;
     5 
     6 char s[maxn];
     7 bool vis[30];
     8 
     9 int main()
    10 {
    11     //freopen("in.txt", "r", stdin);
    12 
    13     int n, cnt = 0;
    14     scanf("%d", &n);
    15     getchar();
    16     for(int i = 0; i < n && cnt < 26; i++)
    17     {
    18         char c = getchar();
    19         int x;
    20         if(c < 'a') x = c - 'A';
    21         else x = c - 'a';
    22         if(!vis[x]) cnt++;
    23         vis[x] = true;
    24     }
    25 
    26     printf("%s
    ", cnt == 26 ? "YES" : "NO");
    27 
    28     return 0;
    29 }
    代码君

    B. Two Buttons (BFS)

    题意:

    最开始有个数字n,有两种按钮,一种可以将这个数字减1,一种按钮可以将这个数字乘2.求将这个数字变为m的最短步数。

    分析:

    一开始以为是DP,后来在纸上演算了一下,发现其实就是一个BFS求最短路。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 10000 + 10;
     5 
     6 int n, m;
     7 int d[maxn];
     8 bool vis[maxn];
     9 
    10 struct Node
    11 {
    12     int u, d;
    13     Node(int u, int d):u(u), d(d) {}
    14 };
    15 
    16 queue<Node> Q;
    17 
    18 int BFS()
    19 {
    20     Node head = Node(n, 0);
    21     vis[n] = true;
    22     Q.push(head);
    23     while(!Q.empty())
    24     {
    25         Node x = Q.front(); Q.pop();
    26 
    27         if(x.u == m) { return x.d; }
    28 
    29         int a = x.u - 1;
    30         int d = x.d + 1;
    31         if(a > 0 && !vis[a])
    32         {
    33             vis[a] = true;
    34             Q.push(Node(a, d));
    35         }
    36 
    37         a = x.u * 2;
    38         if(a < maxn && !vis[a])
    39         {
    40             vis[a] = true;
    41             Q.push(Node(a, d));
    42         }
    43     }
    44     return -1;
    45 }
    46 
    47 int main()
    48 {
    49     //freopen("in.txt", "r", stdin);
    50 
    51     scanf("%d%d", &n, &m);
    52     printf("%d
    ", BFS());
    53 
    54     return 0;
    55 }
    代码君

    C. DNA Alignment (贪心 快速幂)

    题意:

    题目描述还是比较蛋疼的。观察一下,根据题中的定义可以把p(s,t)改写成这样:

    也就是t中的每个DNA都会和s中的每个DNA匹配n次,为了使p(s,t)最大,对于t中的每个DNA只要选择s中出现次数最多的那个即可。

    如果有s中有多种DNA出现的次数最多且相等,选哪种都可以,所以最终答案是kn,其中k是s中重复次数最多的DNA总数。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int maxn = 100000 + 10;
     5 const LL MOD = 1000000007;
     6 int n;
     7 char s[maxn];
     8 
     9 LL pow_mod(LL a, LL n)
    10 {
    11     if(n == 0) return 1LL;
    12     LL ans = pow_mod(a, n >> 1);
    13     ans = ans * ans % MOD;
    14     if(n%2 == 1) ans = ans * a % MOD;
    15     return ans;
    16 }
    17 
    18 int ID(char c)
    19 {
    20     if(c == 'A') return 0;
    21     if(c == 'G') return 1;
    22     if(c == 'C') return 2;
    23     return 3;
    24 }
    25 
    26 int sum[4];
    27 
    28 int main()
    29 {
    30     //freopen("in.txt", "r", stdin);
    31 
    32     scanf("%d", &n);
    33     scanf("%s", s);
    34     for(int i = 0; i < n; i++) sum[ID(s[i])]++;
    35     sort(sum, sum + 4);
    36     reverse(sum, sum + 4);
    37     int i = 1;
    38     while(i < 4 && sum[i] == sum[i - 1]) i++;
    39     LL ans = pow_mod(i, n);
    40     printf("%I64d
    ", ans);
    41 
    42     return 0;
    43 }
    代码君

    D. Cubes (博弈 贪心 模拟)

    题意:

    这道题题意还挺繁琐的。有n个木块,像搭积木一样搭起来,每个木块有自己的编号0~n-1。两个人现在要把积木一块一块的拿下来,而且拿的过程中不会影响其他积木。这样拿积木的顺序就可以看做一个n进制的数(第一个拿下来的积木的编号在最高位)。第一个人想让这个数最大,第二个人想让这个数最小,求最后拿积木所确定下来的数字。

    分析:

    首先如何判断一个积木拿下来不会影响到其他积木,就是判断一下它上方三块积木(如果有的话)是否只被这唯一一块积木支撑着。

    我们可以用C++里面的set来存储可以拿下来的积木的编号,在拿下来一块积木的同时,也可能会暴露出新的积木,如果符合要求的话也要加入到set里面。

    最后再强调一点,并不是加入到set中后就一定可以拿下来,在拿下来的时候还要再判断一次。因为可能发生这样的情况:

    在加入set的时候这块积木可以被拿下来,但是要拿下来这一刻,积木的布局发生变化,这块积木就可能变成了支撑上面积木的唯一一块,所以就不能被拿下来了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define MP make_pair
     4 
     5 const int maxn = 100000 + 10;
     6 const int MOD = 1000000009;
     7 const int dx[] = {-1, 0, 1};
     8 
     9 int x[maxn], y[maxn];
    10 map<pair<int, int>, int> ID;
    11 set<int> Set;
    12 bool vis[maxn];
    13 
    14 bool available(int t)
    15 {
    16     for(int i = 0; i < 3; i++)
    17     {
    18         int nx = x[t] + dx[i];
    19         int ny = y[t] + 1;
    20         int id = ID[MP(nx, ny)];
    21         if(id && !vis[id])
    22         {
    23             int cnt = 0;
    24             for(int j = 0; j < 3; j++)
    25             {
    26                 int nnx = nx + dx[j];
    27                 int nny = y[t];
    28                 int nid = ID[MP(nnx, nny)];
    29                 if(nid && !vis[nid]) cnt++;
    30             }
    31             if(cnt == 1) return false;
    32         }
    33     }
    34     return true;
    35 }
    36 
    37 int main()
    38 {
    39     //freopen("in.txt", "r", stdin);
    40 
    41     int n;
    42     scanf("%d", &n);
    43     for(int i = 1; i <= n; i++)
    44     {
    45         scanf("%d%d", &x[i], &y[i]);
    46         ID[MP(x[i], y[i])] = i;
    47     }
    48 
    49     for(int i = 1; i <= n; i++) if(available(i))
    50         Set.insert(i);
    51 
    52     long long ans = 0;
    53     bool turn = false;
    54     while(Set.size())
    55     {
    56         int t = turn ? *Set.begin() : *Set.rbegin();
    57         Set.erase(t);
    58         if(!available(t)) continue;
    59         turn = !turn;
    60         vis[t] = true;
    61         ans = (ans * n + t - 1) % MOD;
    62         for(int i = 0; i < 3; i++)
    63         {
    64             int nx = x[t] + dx[i];
    65             int ny = y[t] - 1;
    66             int id = ID[MP(nx, ny)];
    67             if(id && !vis[id] && available(id))
    68                 Set.insert(id);
    69         }
    70     }
    71 
    72     printf("%I64d
    ", ans);
    73 }
    代码君

    E. Pluses everywhere (数论 组合数学 乘法逆元)

    题意:

    有一串数字长度为n,要在数字与数字之间加k个加号构成一个表达式,求所有合法表达式的值之和。

    分析:

    插入k个加号会得到k+1个加数,其中这些加数可能存在前导0.考虑每个表达式太麻烦了,不如换个角度,我们固定一个数字d。

    无论加号怎样放,它最终都是贡献d*10l这么多的。具体这个l是多少,就要看它右边离它最近的一个加号有多远;当然也可能它在最后一个加数里面,右边没有加号。

    上面两种情况都要考虑进去,这里只说大概思路好了,官方题解已经说得很详细了。

    其中要求组合数,所以要预处理前n个阶乘以及阶乘的逆元。

    因为刚刚接触乘法逆元这个概念,所以就多说两句:

    如果ax≡1(mod p),则a和x互为关于模p的乘法逆元

    《训练指南》上给出了用扩展欧几里得的算法求乘法逆元的代码,就是解方程:ax + py = 1,找到一组解,x就是a的逆元。

    还有一种办法就是利用费马小定理 或者 欧拉定理,这里以费马小定理为例:

    假如p是质数,且gcd(a,p)=1,那么 a(p-1) ≡1(mod p),那么就有a * a(p-2) ≡ 1 (mod p),所以a(p-2)就是a关于模p的逆元。

    如果是欧拉定理,就有      ,于是aphi(n)-1就是a的逆元,如果n为素数的话,phi(n) = n - 1,所以an-2就是a的逆元。

    所以我们可以统一用快速幂来求乘法逆元了。

    如果是求连续阶乘的逆元,还可以递推来求:

    先求出n的阶乘 fac(n)的逆元inv_fac(n),fac(n) * inv_fac(n) ≡ fac(n-1) * n * inv_fac(n) ≡ 1,所以fac(n-1)的逆元为n * inv_fac(n),这样递推公式就是:

    inv_fac(n-1) = n * inv_fac(n)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 
     5 const int maxn = 100000 + 10;
     6 const int MOD = 1000000007;
     7 
     8 inline LL mul_mod(LL a, LL b, LL n = MOD)
     9 { return a * b % n; }
    10 
    11 LL pow_mod(LL a, LL p, LL n = MOD)
    12 {
    13     if(p == 0) return 1LL;
    14     LL ans = pow_mod(a, p>>1, n);
    15     ans = ans * ans % n;
    16     if(p & 1) ans = ans * a % n;
    17     return ans;
    18 }
    19 
    20 int n, k;
    21 int a[maxn], sum[maxn];
    22 int ten_pow[maxn], fac[maxn], ifac[maxn];
    23 
    24 void Init()
    25 {
    26     sum[0] = a[0];
    27     for(int i = 1; i < n; i++) sum[i] = sum[i - 1] + a[i];
    28 
    29     fac[0] = 1;
    30     for(int i = 1; i <= n; i++) fac[i] = mul_mod(fac[i - 1], i);
    31     ifac[n] = pow_mod(fac[n], MOD - 2);
    32     for(int i = n-1; i >= 0; i--) ifac[i] = mul_mod(ifac[i+1], i+1);
    33 
    34     ten_pow[0] = 1;
    35     for(int i = 1; i < n; i++) ten_pow[i] = mul_mod(ten_pow[i-1], 10);
    36 }
    37 
    38 inline LL C(int n, int k)
    39 {
    40     if(k > n || k < 0) return 0;
    41     return mul_mod(mul_mod(fac[n], ifac[k]), ifac[n-k]);
    42 }
    43 
    44 int main()
    45 {
    46     scanf("%d%d", &n, &k); getchar();
    47     for(int i = 0; i < n; i++) a[i] = getchar() - '0';
    48 
    49     Init();
    50 
    51     LL ans = 0;
    52     for(int l = 0; l <= n-2; l++)
    53     {
    54         ans = (ans + mul_mod(mul_mod(ten_pow[l], C(n-l-2, k-1)), sum[n - l - 2])) % MOD;
    55         ans = (ans + mul_mod(mul_mod(a[l], ten_pow[n-l-1]), C(l, k))) % MOD;
    56     }
    57     ans = (ans + mul_mod(a[n-1], C(n-1, k))) % MOD;
    58     printf("%I64d
    ", ans);
    59 
    60     return 0;
    61 }
    代码君
  • 相关阅读:
    JavaScript | 闭包
    Photoshop | 快速抠头发(调整边缘/选择并遮住)
    JavaScript | 基础表单验证(纯Js)
    JavaScript | 事件
    JavaScript | 数组
    JavaScript | 对象与属性
    JavaScript | 基础(变量/引用/转换/函数)
    Altium Designer 10 | 常用库及部分元件名中英文对照表
    电路 | 基本概念
    读点什么 |《把时间当作朋友》李笑来
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4312194.html
Copyright © 2020-2023  润新知