Codeforces Round #302 (Div. 1) 训练
链接:
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:
- #include<stdio.h>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- #include<vector>
- #include<map>
- #include<set>
- #include<cmath>
- #include<iostream>
- #include<queue>
- #include<string>
- using namespace std;
- typedef long long ll;
- typedef pair<int,int> pii;
- typedef long double ld;
- typedef unsigned long long ull;
- typedef pair<long long,long long> pll;
- #define fi first
- #define se second
- #define pb push_back
- #define mp make_pair
- #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
- #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
- ll read(){
- ll x=,f=;char c=getchar();
- while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
- while(c>='' && c<=''){x=x*+c-'';c=getchar();}
- return x*f;
- }
- const int MAXN = ;
- int mod;
- int a[MAXN];
- int dp[MAXN][MAXN];
- int add(int a, int b)
- {
- return (a + b) % mod;
- }
- int main()
- {
- int n, m, b;
- cin >> n >> m >> b >> mod;
- for (int i = ; i < n; i++)
- cin >> a[i];
- dp[][] = ;
- for (int i = ; i < n; i++)
- for (int j = ; j <= m; j++)
- for (int k = a[i]; k <= b; k++)
- dp[j][k] = add(dp[j][k], dp[j - ][k - a[i]]);
- int ans = ;
- for (int i = ; i <= b; i++)x
- ans = add(ans, dp[m][i]);
- cout << ans << endl;
- }
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:
- #include<stdio.h>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- #include<vector>
- #include<map>
- #include<set>
- #include<cmath>
- #include<iostream>
- #include<queue>
- #include<string>
- using namespace std;
- typedef long long ll;
- typedef pair<int,int> pii;
- typedef long double ld;
- typedef unsigned long long ull;
- typedef pair<long long,long long> pll;
- #define fi first
- #define se second
- #define pb push_back
- #define mp make_pair
- #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
- #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
- ll read(){
- ll x=,f=;char c=getchar();
- while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
- while(c>='' && c<=''){x=x*+c-'';c=getchar();}
- return x*f;
- }
- const int maxn=;
- int n,m;
- vector<int> gr[maxn];
- int dis[maxn][maxn];
- bool vis[maxn];
- void bfs(int u){
- queue<int> q;
- while(!q.empty()) q.pop();
- memset(vis,,sizeof(vis));
- vis[u]=;q.push(u);
- while(!q.empty()){
- int v=q.front();
- q.pop();
- for(int i=;i<gr[v].size();i++){
- int nw=gr[v][i];
- if(vis[nw]) continue;
- vis[nw]=;
- dis[u][nw]=dis[u][v]+;
- q.push(nw);
- }
- }
- }
- int main(){
- n=read(),m=read();
- rep(i,,m){
- int a=read(),b=read();
- gr[a].pb(b),gr[b].pb(a);
- }
- int s1,t1,l1,s2,t2,l2;
- s1=read(),t1=read(),l1=read();
- s2=read(),t2=read(),l2=read();
- rep(i,,n){
- bfs(i);
- }
- if(dis[s1][t1]>l1 || dis[s2][t2]>l2){
- puts("-1");
- return ;
- }
- int ans1=m-dis[s1][t1]-dis[s2][t2];
- int ans2=;
- for(int i=;i<=n;i++){
- for(int j=;j<=n;j++){
- if(i==j) continue;
- int nw=dis[s1][i]+dis[s2][i]+dis[i][j]+dis[j][t1]+dis[j][t2];
- if(dis[s1][i]+dis[i][j]+dis[j][t1]>l1 || dis[s2][i]+dis[i][j]+dis[j][t2]>l2) nw=1e9;
- int nw2=dis[s1][i]+dis[t2][i]+dis[i][j]+dis[j][t1]+dis[j][s2];
- if(dis[s1][i]+dis[i][j]+dis[j][t1]>l1 || dis[t2][i]+dis[i][j]+dis[j][s2]>l2) nw2=1e9;
- ans2=max(ans2,max(m-nw,m-nw2));
- }
- }
- printf("%d\n",max(ans1,ans2));
- return ;
- }
- /*
- 9 9
- 1 2
- 2 3
- 2 4
- 4 5
- 5 7
- 5 6
- 3 8
- 8 9
- 9 6
- 1 7 4
- 3 6 3
- */
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:
- #include <bits/stdc++.h>
- #define forn(i, n) for(int i = 0; i < int(n); i++)
- using namespace std;
- const int N = ;
- const int leng = ;
- string s[N];
- int cost[N][leng], c[N][leng], sv[N][leng], a[N][leng];
- int d[ << N];
- int main() {
- int n, m;
- cin >> n >> m;
- forn(i, n) cin >> s[i];
- forn(i, n) forn(j, m) cin >> a[i][j];
- forn(i, n) {
- forn(j, m) {
- int curv = ;
- forn(k, n) {
- if (s[i][j] == s[k][j]) {
- sv[i][j] |= ( << k);
- c[i][j] += a[k][j];
- curv = max(curv, a[k][j]);
- }
- }
- c[i][j] -= curv;
- }
- }
- forn(i, << n) d[i] = ;
- d[] = ;
- forn(mask, << n) {
- if (mask == ) continue;
- int lowbit = -;
- forn(i, n) {
- if ((mask >> i) & ) {
- lowbit = i;
- break;
- }
- }
- forn(i, m) {
- d[mask] = min(d[mask], d[mask & (mask ^ sv[lowbit][i])] + c[lowbit][i]);
- d[mask] = min(d[mask], d[mask ^ ( << lowbit)] + a[lowbit][i]);
- }
- }
- printf("%d\n", d[( << n) - ]);
- return ;
- }
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:
- #include<stdio.h>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- #include<vector>
- #include<map>
- #include<set>
- #include<cmath>
- #include<iostream>
- #include<queue>
- #include<string>
- using namespace std;
- typedef long long ll;
- typedef pair<int,int> pii;
- typedef long double ld;
- typedef unsigned long long ull;
- typedef pair<long long,long long> pll;
- #define fi first
- #define se second
- #define pb push_back
- #define mp make_pair
- #define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
- #define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
- ll read(){
- ll x=,f=;char c=getchar();
- while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
- while(c>='' && c<=''){x=x*+c-'';c=getchar();}
- return x*f;
- }
- const int mod=;
- int n;
- vector<int> adj[];
- ll dp[],L[],R[];
- ll ans[];
- void dfs(int x){
- dp[x]=;
- for(int i=;i<adj[x].size();i++){
- int v=adj[x][i];
- dfs(v);
- dp[x]=dp[x]*(dp[v]+)%mod;
- }
- }
- void dfs2(int x){
- int num=adj[x].size();
- if(num==) return;
- L[]=,R[num-]=ans[x];
- for(int i=;i<adj[x].size();i++){
- int v=adj[x][i];
- L[i+]=L[i]*(dp[v]+)%mod;
- }
- for(int i=num-;i>=;i--){
- int v=adj[x][i];
- R[i-]=R[i]*(dp[v]+)%mod;
- }
- for(int i=;i<num;i++){
- int v=adj[x][i];
- ans[v]=(L[i]*R[i]+)%mod;
- }
- for(int i=;i<num;i++){
- int v=adj[x][i];
- dfs2(v);
- }
- }
- int main(){
- n=read();
- rep(i,,n){
- int x=read();
- adj[x].pb(i);
- }
- dfs();
- ans[]=;
- dfs2();
- rep(i,,n)
- printf("%lld ",dp[i]*ans[i]%mod);
- puts("");
- return ;
- }
- /*
- 5
- 1 2 3 4
- */
Review:
第一个dp很好想
但是怎么求ans不知道怎么想的
可能需要灵机一动?
Codeforces Round #302 (Div. 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][ ...
- 构造 Codeforces Round #302 (Div. 2) B Sea and Islands
题目传送门 /* 题意:在n^n的海洋里是否有k块陆地 构造算法:按奇偶性来判断,k小于等于所有点数的一半,交叉输出L/S 输出完k个L后,之后全部输出S:) 5 10 的例子可以是这样的: LSLS ...
- 水题 Codeforces Round #302 (Div. 2) A Set of Strings
题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...
- Codeforces Round #549 (Div. 2) 训练实录 (5/6)
The Doors +0 找出输入的01数列里,0或者1先出完的的下标. Nirvana +3 输入n,求1到n的数字,哪个数逐位相乘的积最大,输出最大积. 思路是按位比较,从低到高,依次把小位换成全 ...
- 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 ...
- Codeforces Round #302 (Div. 2) D - Destroying Roads 图论,最短路
D - Destroying Roads Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/544 ...
- 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 ...
- 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 ...
- 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 ...
随机推荐
- adb问题整理
1.开启了两个adb,关掉一个,重启eclipse既可 java.io.IOException: 您的主机中的软件中止了一个已建立的连接. at sun.nio.ch.SocketDispatcher ...
- 修复Xcode升级错误 — PCH File Error
http://www.rockia.net/2013/03/fix-xcode-update-pch-file-error Error:PCH File Built From A Different ...
- date 命令 时间戳到标准格式转换
1. 知道时间戳看标准时间, 时间戳到 秒: Wed Apr :: CST 2. 看到前时间时间戳格式 date +%s 3. 知道某个标准时间, 看时间戳 date -d "Wed Apr ...
- Linux 内核源码中likely()和unlikely()【转】
本文转载自:http://blog.csdn.net/tigerjibo/article/details/8279183 ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们 ...
- javascript XMLHttpRequest 对象的open() 方法参数说明
下文是从w3c上摘录下来的,其中参数 method 说明的很简短,不是很理解,所以又找了些资料作为补充.文中带括号部分. XMLHttpRequest.open() 初始化 HTTP 请求参数 语法o ...
- Oracle:spool 的一个用法
spool 是sqlplus的一个语法,非sql. 平时,我们通过ssh或者xmanger连接到oracle后,如果我们想把我们在上面操作的脚本及脚本执行过程.结果保存下来的话,可以通过spool来实 ...
- 从OutStreamWriter 和Filewriter谈Java编码
首先看JAVA API的描述: ABOUT OutputStreamWriter: "An OutputStreamWriter is a bridge from character str ...
- Windows命令行bat批处理延迟sleep方法
使用ping 的定时功能,精度1秒 实战:创建示例文件test.bat,内容如下: 代码如下:ping -n 3 127.0.0.1>nul 说明:3为ping包发送次数,可作为延迟秒数进行使用 ...
- CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset+bfs
CF_576D_Flights for Regular Customers_矩阵乘法+倍增floyd+bitset https://www.luogu.org/problemnew/show/CF57 ...
- bzoj 2238 Mst —— 树剖+mn标记永久化
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238 看了半天... 首先,想要知道每条边删除之后的替代中最小的那个: 反过来看,每条不在 ...