Codeforces Round #302 (Div. 1)

A题是个背包问题。给你n个一行代码,第 i 代码写的时候会产生 ai 个bug,要写 m 行,总的bug不能超过 b 个,问有多少种方案,对mod取模。

dp[i][j][k] = (dp[i-1][j][k] + dp[i][j-1][k-a[i]]) % mod; 表示不选第 i 个的话就有 dp[i-1][j][k], 选第 i 个就有 dp[i][j-1][k-a[i]]种方案。滚动数组节省空间

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <algorithm>
 7 
 8 using namespace std;
 9 
10 #define LL long long
11 #define eps 1e-8
12 #define inf 0x3f3f3f3f
13 #define N 510
14 #define M 200020
15 
16 int dp[2][N][N], a[N];
17 int main(){
18     int n, m, b, mod;
19     scanf("%d%d%d%d", &n, &m, &b, &mod);
20     for(int i = 1; i <= n; ++i)
21         scanf("%d", &a[i]);
22     dp[0][0][0] = 1;
23     int cur = 1, last = 0;
24     for(int i = 1; i <= n; ++i){
25         for(int j = 0; j <= m; ++j){
26             for(int k = b; k >= a[i]; --k)
27                 if(j == 0) dp[cur][j][k] = dp[last][j][k];
28                 else dp[cur][j][k] = (dp[last][j][k] + dp[cur][j-1][k-a[i]]) % mod;
29             for(int k = a[i] - 1; k >= 0; --k)
30                 dp[cur][j][k] = dp[last][j][k];
31         }
32         cur ^= 1;
33         last ^= 1;
34         memset(dp[cur], 0, sizeof dp[cur]);
35     }
36     int ans = 0;
37     for(int i = 0; i <= b; ++i)
38         ans = (ans + dp[last][m][i]) % mod;
39     printf("%d\n", ans);
40     return 0;
41 }
View Code

B题。问你删掉最多能删掉多少条边,仍然使得s1到t1的距离不大于 l1,s2到t2的距离不大于 l2。

最后剩下的图中,s1 - t1 和 s2 - t2必须能够有通路满足题目的条件,且d[s1][t1], d[s2][t2]要尽量小,这样才能够删尽量多的边。

假如d[s1][t1], d[s2][t2]没有公共边,ans = m - d[s1][t1] - d[s2][t2]。如果有公共边,就n^2枚举公共边的两端,ans = max(ans,ans - d1 - d2 - d[i][j])具体看代码理解d1,d2的含义。

做法就是bfs预处理每两点之间的距离,然后枚举公共边的两端。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-8
13 #define inf 0x3f3f3f3f
14 #define N 3010
15 #define M 5000020
16 
17 int fst[N], nxt[M], vv[M], d[N][N], e;
18 bool vis[N];
19 void init(){
20     memset(fst, -1, sizeof fst);
21     e = 0;
22 }
23 void add(int u, int v){
24     vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
25 }
26 void bfs(int s){
27     queue<int> q;
28     d[s][s] = 0;
29     q.push(s);
30     vis[s] = 1;
31     while(!q.empty()){
32         int u = q.front(); q.pop();
33         for(int i = fst[u]; ~i; i = nxt[i]){
34             int v = vv[i];
35             if(!vis[v])
36                 vis[v] = 1, d[s][v] = d[s][u] + 1, q.push(v);
37         }
38     }
39 }
40 int main(){
41     init();
42     int n, m;
43     scanf("%d%d", &n, &m);
44     for(int i = 0; i < m; ++i){
45         int u, v;
46         scanf("%d%d", &u, &v);
47         add(u, v), add(v, u);
48     }
49     int a, b, t1, x, y, t2;
50     scanf("%d%d%d%d%d%d", &a, &b, &t1, &x, &y, &t2);
51     for(int i = 1; i <= n; ++i){
52         memset(vis, 0, sizeof vis);
53         bfs(i);
54     }
55     if(d[a][b] > t1 || d[x][y] > t2){
56         puts("-1"); return 0;
57     }
58     int ans = max(0, m - d[a][b] - d[x][y]);
59     for(int i = 1; i <= n; ++i)
60     for(int j = 1; j <= n; ++j){
61         int d1 = min(d[a][i] + d[b][j], d[a][j] + d[b][i]);
62         int d2 = min(d[x][i] + d[y][j], d[x][j] + d[y][i]);
63         if(d1 + d[i][j] > t1 || d2 + d[i][j] > t2) continue;
64         ans = max(ans, m - d1 - d2 - d[i][j]);
65     }
66     printf("%d\n", ans);
67     return 0;
68 }
View Code

D题。以 1 为根的话dfs,易想到dp[u] = dp[u] * (dp[v] + 1) ( (u, v)这条边不修复的情况,那么后面所有边都要修复,就只有1种情况。(u, v)这条边要是修复的话,那么后面就有dp[v]种情况)。

然后再进行第二次dfs,dp[v] = (1 + dp[u] / (dp[v] + 1) ) * dp[v]  ( (v, u)这条边不修复的话,就只有1种情况。(u, v)这条边要是修复了,就有dp[u] / (dp[v] + 1)种情况。

因为要取模,dp[u] / (dp[v] + 1)要求逆元。题目构造的数据取模的话会跪。所以就用pre和pos保存节点u下面的所有儿子的乘积前缀积 和 后缀积。具体看代码吧。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <vector>
 9 
10 using namespace std;
11 
12 #define LL long long
13 #define eps 1e-8
14 #define inf 0x3f3f3f3f
15 #define N 200010
16 #define M 400020
17 #define mod 1000000007
18 
19 int fst[N], e, nxt[M], vv[M];
20 void init(){
21     memset(fst, -1, sizeof fst);
22     e = 0;
23 }
24 void add(int u, int v){
25     vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
26 }
27 LL dp[N], f[N];
28 vector<int> g[N];
29 void dfs1(int u, int p){
30     dp[u] = 1;
31     for(int i = fst[u]; ~i; i = nxt[i]){
32         int v = vv[i];
33         if(v == p) continue;
34         g[u].push_back(v);
35         dfs1(v, u);
36         dp[u] = dp[u] * (1 + dp[v]) % mod;
37     }
38 }
39 LL pre[N], pos[N];
40 void dfs2(int u){
41     int all = g[u].size();
42     if(all == 0) return ;
43     pre[0] = pos[all] = 1;
44     for(int i = 1; i <= all; ++i){
45         int v = g[u][i-1];
46         pre[i] = pre[i-1] * (dp[v] + 1) % mod;
47     }
48     for(int i = all - 1; i >= 0; --i){
49         int v = g[u][i];
50         pos[i] = pos[i+1] * (dp[v] + 1) % mod;
51     }
52     for(int i = 0; i < all; ++i){
53         int v = g[u][i];
54         f[v] = f[u] * pre[i] % mod * pos[i+1] % mod;
55         f[v] = (f[v] + 1) % mod;
56     }
57     for(int i = 0; i < all; ++i)
58         dfs2(g[u][i]);
59 }
60 int main(){
61     init();
62     int n;
63     scanf("%d", &n);
64     for(int i = 2; i <= n; ++i){
65         int v;
66         scanf("%d", &v);
67         add(i, v), add(v, i);
68     }
69     dfs1(1, -1);
70     f[1] = 1;
71     dfs2(1);
72     for(int i = 1; i <= n; ++i){
73         printf("%I64d ", f[i] * dp[i] % mod);
74     }
75     cout << endl;
76     return 0;
77 }
View Code

 

posted @ 2015-07-21 00:10  L__J  阅读(165)  评论(0编辑  收藏  举报