链接:

http://codeforces.com/contest/543

过程:

惨淡的只做出了A和C

题解:

A

题解:

简单的一道题

我们用$dp[i][j]$表示当前考虑到前num个人(这个另外枚举),当前写了$i$行代码,当前的bug数量为$j$的方案数

然后转移就是$dp[i][j]=\sum {dp[i-1][j-a[num]]}$

Code:

  1. #include<stdio.h>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<vector>
  6. #include<map>
  7. #include<set>
  8. #include<cmath>
  9. #include<iostream>
  10. #include<queue>
  11. #include<string>
  12. using namespace std;
  13. typedef long long ll;
  14. typedef pair<int,int> pii;
  15. typedef long double ld;
  16. typedef unsigned long long ull;
  17. typedef pair<long long,long long> pll;
  18. #define fi first
  19. #define se second
  20. #define pb push_back
  21. #define mp make_pair
  22. #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
  23. #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
  24.  
  25. ll read(){
  26. ll x=,f=;char c=getchar();
  27. while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
  28. while(c>='' && c<=''){x=x*+c-'';c=getchar();}
  29. return x*f;
  30. }
  31.  
  32. const int MAXN = ;
  33.  
  34. int mod;
  35. int a[MAXN];
  36. int dp[MAXN][MAXN];
  37.  
  38. int add(int a, int b)
  39. {
  40. return (a + b) % mod;
  41. }
  42.  
  43. int main()
  44. {
  45. int n, m, b;
  46. cin >> n >> m >> b >> mod;
  47. for (int i = ; i < n; i++)
  48. cin >> a[i];
  49. dp[][] = ;
  50. for (int i = ; i < n; i++)
  51. for (int j = ; j <= m; j++)
  52. for (int k = a[i]; k <= b; k++)
  53. dp[j][k] = add(dp[j][k], dp[j - ][k - a[i]]);
  54. int ans = ;
  55. for (int i = ; i <= b; i++)x
  56. ans = add(ans, dp[m][i]);
  57. cout << ans << endl;
  58. }

Review:

比较容易的一道题

B

题解:

首先可以通过BFS得到dis[i][j]数组,也就是任意两点的最短路

然后分两种情况

1. 只剩下s1到t1,s2到t2的最短路 代价:m-dis[s1][t1]-dis[s2][t2]

2. 剩下的两条路径有交,组成一个‘H’形状

代价:枚举i,j表示那个交集的两端

然后剩下的边数的可能情况就是dis[s1][i]+dis[s2][i]+dis[i][j]+dis[j][t1]+dis[j][t2] 或者 dis[s1][i]+dis[t2][i]+dis[i][j]+dis[j][t1]+dis[j][s2]

取一个最小值 再用m减去就好了

注意判断这样的i,j不满足l1,l2的要求的情况

Code:

  1. #include<stdio.h>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<vector>
  6. #include<map>
  7. #include<set>
  8. #include<cmath>
  9. #include<iostream>
  10. #include<queue>
  11. #include<string>
  12. using namespace std;
  13. typedef long long ll;
  14. typedef pair<int,int> pii;
  15. typedef long double ld;
  16. typedef unsigned long long ull;
  17. typedef pair<long long,long long> pll;
  18. #define fi first
  19. #define se second
  20. #define pb push_back
  21. #define mp make_pair
  22. #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
  23. #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
  24.  
  25. ll read(){
  26. ll x=,f=;char c=getchar();
  27. while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
  28. while(c>='' && c<=''){x=x*+c-'';c=getchar();}
  29. return x*f;
  30. }
  31.  
  32. const int maxn=;
  33. int n,m;
  34. vector<int> gr[maxn];
  35. int dis[maxn][maxn];
  36. bool vis[maxn];
  37.  
  38. void bfs(int u){
  39. queue<int> q;
  40. while(!q.empty()) q.pop();
  41. memset(vis,,sizeof(vis));
  42. vis[u]=;q.push(u);
  43. while(!q.empty()){
  44. int v=q.front();
  45. q.pop();
  46. for(int i=;i<gr[v].size();i++){
  47. int nw=gr[v][i];
  48. if(vis[nw]) continue;
  49. vis[nw]=;
  50. dis[u][nw]=dis[u][v]+;
  51. q.push(nw);
  52. }
  53. }
  54. }
  55.  
  56. int main(){
  57. n=read(),m=read();
  58. rep(i,,m){
  59. int a=read(),b=read();
  60. gr[a].pb(b),gr[b].pb(a);
  61. }
  62. int s1,t1,l1,s2,t2,l2;
  63. s1=read(),t1=read(),l1=read();
  64. s2=read(),t2=read(),l2=read();
  65.  
  66. rep(i,,n){
  67. bfs(i);
  68. }
  69.  
  70. if(dis[s1][t1]>l1 || dis[s2][t2]>l2){
  71. puts("-1");
  72. return ;
  73. }
  74. int ans1=m-dis[s1][t1]-dis[s2][t2];
  75. int ans2=;
  76. for(int i=;i<=n;i++){
  77. for(int j=;j<=n;j++){
  78. if(i==j) continue;
  79. int nw=dis[s1][i]+dis[s2][i]+dis[i][j]+dis[j][t1]+dis[j][t2];
  80. if(dis[s1][i]+dis[i][j]+dis[j][t1]>l1 || dis[s2][i]+dis[i][j]+dis[j][t2]>l2) nw=1e9;
  81. int nw2=dis[s1][i]+dis[t2][i]+dis[i][j]+dis[j][t1]+dis[j][s2];
  82. if(dis[s1][i]+dis[i][j]+dis[j][t1]>l1 || dis[t2][i]+dis[i][j]+dis[j][s2]>l2) nw2=1e9;
  83. ans2=max(ans2,max(m-nw,m-nw2));
  84. }
  85. }
  86. printf("%d\n",max(ans1,ans2));
  87. return ;
  88. }
  89.  
  90. /*
  91. 9 9
  92. 1 2
  93. 2 3
  94. 2 4
  95. 4 5
  96. 5 7
  97. 5 6
  98. 3 8
  99. 8 9
  100. 9 6
  101. 1 7 4
  102. 3 6 3
  103. */

Review:

我竟然连能够求出dis数组都没看出来

傻傻的以为要floyd或者n遍dijkstra

没注意到边权为1。。。

所以边权为1----BFS

C

题解:

很显然要用状压dp

(毕竟20的数据范围摆在那里)

那么令$dp[mask]$表示将mask对应的字符串变成easy to remember的最小代价

复杂度最多只能为$O(2^n \times n)$ 所以还可以枚举一层

那么怎么做呢

考虑转移:

首先我们不能做到O(1)转移

所以不能枚举每一个属于mask的字符串

那么我们必须做到对于任意一个属于mask的字符串 通过我们的转移都能够得到答案

所以必须得有两种转移

我们令选取的字符串为$s_i$,剩下的状态为$nwmask$

1. 把$s_i$改动一位,并压进去

因为最多20个字符串而有26个字母,所以可以保证改任意一位都可行

那肯定选择最少的代价的那一位去修改

2. 改动其他的字符串的某一位,使得他们和$s_i$的这一位都不同

这个代价是可以预处理的

Code:

  1. #include <bits/stdc++.h>
  2.  
  3. #define forn(i, n) for(int i = 0; i < int(n); i++)
  4.  
  5. using namespace std;
  6.  
  7. const int N = ;
  8. const int leng = ;
  9. string s[N];
  10. int cost[N][leng], c[N][leng], sv[N][leng], a[N][leng];
  11. int d[ << N];
  12.  
  13. int main() {
  14. int n, m;
  15. cin >> n >> m;
  16. forn(i, n) cin >> s[i];
  17. forn(i, n) forn(j, m) cin >> a[i][j];
  18.  
  19. forn(i, n) {
  20. forn(j, m) {
  21. int curv = ;
  22. forn(k, n) {
  23. if (s[i][j] == s[k][j]) {
  24. sv[i][j] |= ( << k);
  25. c[i][j] += a[k][j];
  26. curv = max(curv, a[k][j]);
  27. }
  28. }
  29. c[i][j] -= curv;
  30. }
  31. }
  32. forn(i, << n) d[i] = ;
  33. d[] = ;
  34. forn(mask, << n) {
  35. if (mask == ) continue;
  36. int lowbit = -;
  37. forn(i, n) {
  38. if ((mask >> i) & ) {
  39. lowbit = i;
  40. break;
  41. }
  42. }
  43. forn(i, m) {
  44. d[mask] = min(d[mask], d[mask & (mask ^ sv[lowbit][i])] + c[lowbit][i]);
  45. d[mask] = min(d[mask], d[mask ^ ( << lowbit)] + a[lowbit][i]);
  46. }
  47. }
  48. printf("%d\n", d[( << n) - ]);
  49. return ;
  50. }

Review:

我觉得挺难的,但是怎么那么多人随手切啊

D

题解:

首先如果只要算1为根的答案是个很简单的树形dp

用$dp[i]$表示以i为根的子树的答案

$dp[i]=\prod {(dp[son]+1)}$

然后我们考虑怎么算每个点的答案

我们通过父亲的答案求儿子的答案

怎么做呢?

首先我们看从父亲到儿子有哪些变化

我们用ans[i]记录i结点对应的上方给i的贡献 然后再乘上dp[i](i的下方对i的贡献)就是i为根的答案

我们怎么计算ans数组呢

发现从父亲到儿子的变化就在于多了几个儿子对应的兄弟

$ans[son]=ans[father] \times \prod {(dp[brother]+1)}$

所以我们记录L,R表示当前结点的儿子们的前缀(dp+1)的积,后缀(dp+1)的积

然后$ans[son]=ans[father]*L[son]*R[son]*ans[father]+1$就可以了

+1指的是把儿子的父亲当作儿子的儿子的时候计算答案的时候要把dp+1相乘

Code:

  1. #include<stdio.h>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<vector>
  6. #include<map>
  7. #include<set>
  8. #include<cmath>
  9. #include<iostream>
  10. #include<queue>
  11. #include<string>
  12. using namespace std;
  13. typedef long long ll;
  14. typedef pair<int,int> pii;
  15. typedef long double ld;
  16. typedef unsigned long long ull;
  17. typedef pair<long long,long long> pll;
  18. #define fi first
  19. #define se second
  20. #define pb push_back
  21. #define mp make_pair
  22. #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
  23. #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
  24.  
  25. ll read(){
  26. ll x=,f=;char c=getchar();
  27. while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
  28. while(c>='' && c<=''){x=x*+c-'';c=getchar();}
  29. return x*f;
  30. }
  31.  
  32. const int mod=;
  33. int n;
  34. vector<int> adj[];
  35. ll dp[],L[],R[];
  36. ll ans[];
  37.  
  38. void dfs(int x){
  39. dp[x]=;
  40. for(int i=;i<adj[x].size();i++){
  41. int v=adj[x][i];
  42. dfs(v);
  43. dp[x]=dp[x]*(dp[v]+)%mod;
  44. }
  45. }
  46.  
  47. void dfs2(int x){
  48. int num=adj[x].size();
  49. if(num==) return;
  50. L[]=,R[num-]=ans[x];
  51. for(int i=;i<adj[x].size();i++){
  52. int v=adj[x][i];
  53. L[i+]=L[i]*(dp[v]+)%mod;
  54. }
  55. for(int i=num-;i>=;i--){
  56. int v=adj[x][i];
  57. R[i-]=R[i]*(dp[v]+)%mod;
  58. }
  59. for(int i=;i<num;i++){
  60. int v=adj[x][i];
  61. ans[v]=(L[i]*R[i]+)%mod;
  62. }
  63. for(int i=;i<num;i++){
  64. int v=adj[x][i];
  65. dfs2(v);
  66. }
  67. }
  68.  
  69. int main(){
  70. n=read();
  71. rep(i,,n){
  72. int x=read();
  73. adj[x].pb(i);
  74. }
  75. dfs();
  76. ans[]=;
  77. dfs2();
  78. rep(i,,n)
  79. printf("%lld ",dp[i]*ans[i]%mod);
  80. puts("");
  81. return ;
  82. }
  83.  
  84. /*
  85. 5
  86. 1 2 3 4
  87. */

Review:

第一个dp很好想

但是怎么求ans不知道怎么想的

可能需要灵机一动

Codeforces Round #302 (Div. 1) 训练的更多相关文章

  1. 完全背包 Codeforces Round #302 (Div. 2) C Writing Code

    题目传送门 /* 题意:n个程序员,每个人每行写a[i]个bug,现在写m行,最多出现b个bug,问可能的方案有几个 完全背包:dp[i][j][k] 表示i个人,j行,k个bug dp[0][0][ ...

  2. 构造 Codeforces Round #302 (Div. 2) B Sea and Islands

    题目传送门 /* 题意:在n^n的海洋里是否有k块陆地 构造算法:按奇偶性来判断,k小于等于所有点数的一半,交叉输出L/S 输出完k个L后,之后全部输出S:) 5 10 的例子可以是这样的: LSLS ...

  3. 水题 Codeforces Round #302 (Div. 2) A Set of Strings

    题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...

  4. Codeforces Round #549 (Div. 2) 训练实录 (5/6)

    The Doors +0 找出输入的01数列里,0或者1先出完的的下标. Nirvana +3 输入n,求1到n的数字,哪个数逐位相乘的积最大,输出最大积. 思路是按位比较,从低到高,依次把小位换成全 ...

  5. Codeforces Round #302 (Div. 1) C. Remembering Strings DP

    C. Remembering Strings Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/5 ...

  6. Codeforces Round #302 (Div. 2) D - Destroying Roads 图论,最短路

    D - Destroying Roads Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544 ...

  7. Codeforces Round #302 (Div. 2) C. Writing Code 简单dp

    C. Writing Code Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544/prob ...

  8. Codeforces Round #302 (Div. 2) B. Sea and Islands 构造

    B. Sea and Islands Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544/p ...

  9. Codeforces Round #302 (Div. 2) A. Set of Strings 水题

    A. Set of Strings Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544/pr ...

随机推荐

  1. adb问题整理

    1.开启了两个adb,关掉一个,重启eclipse既可 java.io.IOException: 您的主机中的软件中止了一个已建立的连接. at sun.nio.ch.SocketDispatcher ...

  2. 修复Xcode升级错误 — PCH File Error

    http://www.rockia.net/2013/03/fix-xcode-update-pch-file-error Error:PCH File Built From A Different ...

  3. date 命令 时间戳到标准格式转换

    1. 知道时间戳看标准时间, 时间戳到 秒: Wed Apr :: CST 2. 看到前时间时间戳格式 date +%s 3. 知道某个标准时间, 看时间戳 date -d "Wed Apr ...

  4. Linux 内核源码中likely()和unlikely()【转】

    本文转载自:http://blog.csdn.net/tigerjibo/article/details/8279183 ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们 ...

  5. javascript XMLHttpRequest 对象的open() 方法参数说明

    下文是从w3c上摘录下来的,其中参数 method 说明的很简短,不是很理解,所以又找了些资料作为补充.文中带括号部分. XMLHttpRequest.open() 初始化 HTTP 请求参数 语法o ...

  6. Oracle:spool 的一个用法

    spool 是sqlplus的一个语法,非sql. 平时,我们通过ssh或者xmanger连接到oracle后,如果我们想把我们在上面操作的脚本及脚本执行过程.结果保存下来的话,可以通过spool来实 ...

  7. 从OutStreamWriter 和Filewriter谈Java编码

    首先看JAVA API的描述: ABOUT OutputStreamWriter: "An OutputStreamWriter is a bridge from character str ...

  8. Windows命令行bat批处理延迟sleep方法

    使用ping 的定时功能,精度1秒 实战:创建示例文件test.bat,内容如下: 代码如下:ping -n 3 127.0.0.1>nul 说明:3为ping包发送次数,可作为延迟秒数进行使用 ...

  9. CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset+bfs

    CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset https://www.luogu.org/problemnew/show/CF57 ...

  10. bzoj 2238 Mst —— 树剖+mn标记永久化

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238 看了半天... 首先,想要知道每条边删除之后的替代中最小的那个: 反过来看,每条不在 ...