• 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
    ", 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
    ", 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
  • 相关阅读:
    bind 与Eval的区别
    GDI+
    文件读写
    “六度分离”和 洪泛(Search flooding)搜索
    Internet streaming 现在谁是霸主?
    苹果提供高清HD下载SO贵
    关于Youtube 的平均文件尺寸与GFS
    [笔记+整理]随机网络和无标度网络
    2008年中国广播电视广告额增长超15%
    笔记:Mobile CDN 和IPTV CDN有哪些不同
  • 原文地址:https://www.cnblogs.com/LJ-blog/p/4663183.html
Copyright © 2020-2023  润新知