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 ", ans); 40 return 0; 41 }
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 ", ans); 67 return 0; 68 }
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 }