• Codeforces Round #369 (Div. 2)


    A

    模拟 找到两个相邻的O变成X。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 char s[1005][10];
     5 int main () {
     6     bool ok = false;
     7     int n; scanf("%d", &n);
     8     for(int i = 1; i <= n; ++ i) {
     9         scanf("%s", s[i] + 1);
    10         if(!ok && s[i][1] == 'O' && s[i][2] == 'O') ok = true, s[i][1] = s[i][2] = '+';
    11         if(!ok && s[i][4] == 'O' && s[i][5] == 'O') ok = true, s[i][4] = s[i][5] = '+';
    12     }
    13     if(!ok) puts("NO");
    14     else {
    15         puts("YES");
    16         for(int i = 1; i <= n; ++ i) puts(s[i] + 1);
    17     }
    18     return 0;
    19 }
    View Code

    B

    题意:给一个n×n的矩阵,其中每个矩阵有且只有一个数是0,其他都是大于零的数,问能否在这个值为0的位置填上一个大于0的数使得矩阵的每行、每列和对角线的和都相等

    思路:按一维找到这个数后在判断其他维是否满足。(注意要用long long)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 long long a[505][505];
     5 pair<long long, int>sum1[505], sum2[505];
     6 int main () {
     7     int n; scanf("%d", &n);
     8     for(int i = 1; i <= n; ++ i) {
     9         for(int j = 1; j <= n; ++ j) {
    10             scanf("%lld", &a[i][j]);
    11             sum1[i].first += a[i][j], sum1[i].second = i;
    12             sum2[j].first += a[i][j], sum2[j].second = j;
    13         }
    14     }
    15     if(n == 1) return 0 * puts("1");
    16     sort(sum1 + 1, sum1 + 1 + n), sort(sum2 + 1, sum2 + 1 + n);
    17     if(sum1[1].first >= sum1[2].first || sum1[2].first != sum1[n].first) return 0 * puts("-1");
    18     if(sum2[1].first >= sum2[2].first || sum2[2].first != sum2[n].first) return 0 * puts("-1");
    19     if(sum1[1].first != sum2[1].first || sum1[2].first != sum2[2].first) return 0 * puts("-1");
    20     long long ans = sum1[2].first - sum1[1].first;
    21     a[sum1[1].second][sum2[1].second] = ans;
    22     long long x = 0, y = 0;
    23     for(int i = 1; i <= n; ++ i) x += a[i][i], y += a[i][n - i + 1];
    24     if(x != y || x != sum1[2].first) return 0 * puts("-1");
    25     printf("%lld
    ", ans);
    26     return 0;
    27 }
    View Code

    C

    题意:n棵树,m种颜色,这些树有些已经涂了颜色有些没涂,可以花费p[i][j]的价值给没有涂色的第i棵树涂上第j种颜色,问最终把树涂成恰好k段花费的最小价值,(相同颜色为一段)

    思路: dp[i][j][k]表示涂到第i棵树,用的颜料是第j种,当前被分成了k段的最小价值,暴力转移下。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int color[105];
     5 long long p[105][105];
     6 long long dp[105][105][105];
     7 //pos
     8 //select
     9 //num
    10 
    11 void update(long long &x, long long y) {
    12     if(x == -1) x = y;
    13     else if(x > y) x = y;
    14 }
    15 
    16 int main () {
    17     int n, m, K; scanf("%d%d%d", &n, &m, &K);
    18     for(int i = 1; i <= n; ++ i) scanf("%d", color + i);
    19     for(int i = 1; i <= n; ++ i) for(int j = 1; j <= m; ++ j) scanf("%lld", &p[i][j]);
    20     memset(dp, -1, sizeof dp), dp[0][0][0] = 0;
    21     for(int i = 0; i <= n - 1; ++ i) {
    22         for(int j = 0; j <= m; ++ j) {
    23             for(int k = 0; k <= K; ++ k) if(dp[i][j][k] != -1) {
    24                 for(int l = 1; l <= m; ++ l) {
    25                     if(color[i + 1] != 0) {
    26                         if(l == color[i + 1]) {
    27                             update(dp[i + 1][l][k + (j == l ? 0 : 1)], dp[i][j][k] + p[i + 1][l]);
    28                         }
    29                     } else {
    30                         update(dp[i + 1][l][k + (j == l ? 0 : 1)], dp[i][j][k] + p[i + 1][l]);
    31                     }
    32                 }
    33             }
    34         }
    35     }
    36     long long ans = 1LL << 50;
    37     for(int i = 1; i <= m; ++ i) if(dp[n][i][K] != -1) ans = min(ans, dp[n][i][K]);
    38     if(ans == 1LL << 50) return 0 * puts("-1");
    39     else {
    40         for(int i = 1; i <= n; ++ i) if(color[i]) ans -= p[i][color[i]];
    41         printf("%lld
    ", ans);
    42     }
    43     return 0;
    44 }
    View Code

    D

    题意:n个点,每个点对a[i](a[i] != i)这个点有一条单向边,问选择一些边,把它们转向后这个图没有环的方案数。

    思路:如果x个点是一个环,那么总共有2^x种选择方案,其中都选和都不选不符合要求,那么有2^x - 2种方案可行,如果一条边不属于某条环,那么转不转这条边都不会成环,有2种方案可行。求出环后把方案数乘起来就是答案。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int mod = 1e9 + 7;
     5 
     6 int p[200005], p2[200005], cnt[200005];
     7 
     8 int dfn[200005], low[200005], belong[200005], scc, bnum;
     9 
    10 stack<int>sta;
    11 void tarjan(int u) {
    12     dfn[u] = low[u] = ++ scc;
    13     sta.push(u);
    14     if(dfn[p[u]] == 0) tarjan(p[u]), low[u] = min(low[u], low[p[u]]);
    15     else if(!belong[p[u]]) low[u] = min(low[u], dfn[p[u]]);
    16     if(low[u] == dfn[u]) {
    17         ++ bnum;
    18         int v;
    19         do {
    20             v = sta.top(); sta.pop();
    21             belong[v] = bnum;
    22         } while(u != v);
    23     }
    24 }
    25 
    26 int main () {
    27     p2[0] = 1;
    28     for(int i = 1; i <= 200000; ++ i) p2[i] = p2[i - 1] * 2 % mod;
    29     int n; scanf("%d", &n);
    30     for(int i = 1; i <= n; ++ i) scanf("%d", p + i);
    31     for(int i = 1; i <= n; ++ i) if(!belong[i]) tarjan(i);
    32     for(int i = 1; i <= n; ++ i) cnt[belong[i]] ++;
    33     int ans = 1;
    34     for(int i = 1; i <= n; ++ i) {
    35         if(cnt[i] == 1) ans = ans * 2 % mod;
    36         else if(cnt[i] > 1) ans = 1LL * ans * (p2[cnt[i]] + mod - 2) % mod;
    37     }
    38     printf("%d
    ", ans);
    39     return 0;
    40 }
    View Code

    E

    题意:一个地方一年有2^n天,问k个人至少有两个人是同一天生日的概率。最后以最简分数的形式表达。数字太大,那么在对1000003取余输出。

    思路:如果2^n < m,根据鸽巢原理,答案为1/1,否则答案为1 - 2^n *(2^n-1)*……*(2^n-(m-1))/ 2^nm,分母好算,分子的话注意到mod=1e6+3,连续1e6+3个数相乘取余即为0,那么暴力算。算最简分数时发现分母只有2这个因子,于是去找分母中这个因子,然后分子分母求个逆元。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int mod = 1e6 + 3;
     5 
     6 long long fp(long long a, long long b) {
     7     long long res = 1;
     8     while(b) {
     9         if(b & 1) res = res * a % mod;
    10         if(b >>= 1) a = a * a % mod;
    11     }
    12     return res;
    13 }
    14 
    15 long long cal(long long n, long long k) {
    16     long long res = 1, x = fp(2, n % ( mod - 1));
    17     for(long long i = 0; i <= k - 1; ++ i) {
    18         res = res * (x - i + mod) % mod;
    19         if(res == 0) return 0;
    20     }
    21     return res;
    22 }
    23 
    24 int main () {
    25     long long n, k; scanf("%lld%lld", &n, &k);
    26     if(n <= 60 && (1LL << n) < k) return 0 * puts("1 1");
    27     if(k == 1) return 0 * puts("0 1");
    28     long long A = cal(n, k);
    29     long long B = fp(2, (n % (mod - 1)) * (k % (mod - 1)) % (mod - 1));
    30     long long x = n; -- k;
    31     while(k) k /= 2, x += k;
    32     x = fp(2, x % (mod - 1)), A = A * fp(x, mod - 2) % mod, B = B * fp(x, mod - 2) % mod;
    33     printf("%lld %lld
    ", (B - A + mod) % mod, B % mod);
    34     return 0;
    35 }
    View Code
  • 相关阅读:
    搜狗输入法--评价
    课堂练习--找水王
    学习进度条---第十二周
    Java接口与继承动手动脑
    Java数组课后作业
    Java语言String字符串课后作业
    Java类和对象课后作业
    Java语言第四讲
    Java语法基础----课后实践作业
    Java课堂作业-------参数求和
  • 原文地址:https://www.cnblogs.com/youqiong/p/5821784.html
Copyright © 2020-2023  润新知