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\n", 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\n", 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\n", 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\n", (B - A + mod) % mod, B % mod);
34     return 0;
35 }
View Code

 

posted @ 2016-08-30 14:08  youqiong  阅读(116)  评论(0编辑  收藏  举报