题目链接:http://codeforces.com/gym/101196
小结:BCE题没啥好说的,F是dp,有可取之处。G是一道思维题(但是还没有全懂qls的思路)。I题是一个简单最大流。D是一个简单bfs吧(还没写对)。H好像是个瞎搞题,没写。
updata:2018年5月28日22:25:47
B - Foosball Dynasty (模拟)
思路:依照题意模拟即可
#include <bits/stdc++.h>
using namespace std;
string name[10 + 5];
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
cin >> name[i];
}
int wwin = 0, bwin = 0;
string wo = name[0], bo = name[1], wd = name[2], bd = name[3];
string wfirst = name[0], wsecond = name[2], bfirst = name[1], bsecond = name[3];
queue<string>que;
for(int i = 4; i < n; i++) que.push(name[i]);
string str;
cin >> str;
int ans = 0;
vector<pair<string, string>>vec;
for(int i = 0; i < str.size(); i++)
{
if(str[i] == 'W')
{// white win
swap(wd, wo);
que.push(bd);
bd = bo;
bo = que.front();que.pop();
bfirst = bd;
bsecond = bo;
wwin++;
bwin = 0;
if(wwin > ans)
{
ans = wwin;
vec.clear();
vec.push_back({wfirst, wsecond});
}
else if(wwin == ans) vec.push_back({wfirst, wsecond});
}
else
{//black win
swap(bd, bo);
que.push(wd);
wd = wo;
wo = que.front();que.pop();
wfirst = wd;
wsecond = wo;
bwin++;
wwin = 0;
if(bwin > ans)
{
ans = bwin;
vec.clear();
vec.push_back({bfirst, bsecond});
}
else if(bwin == ans) vec.push_back({bfirst, bsecond});
}
}
for(auto o : vec) cout << o.first << " " << o.second <<endl;
return 0;
}
C - The Key to Cryptography(water)
#include <bits/stdc++.h>
using namespace std;
int main()
{
string cip, key;
cin >> cip >> key;
string plain = "";
for(int i = 0; i < cip.size(); i++)
{
int off = key[i] - 'A';
char temp = (cip[i] - 'A' + 26 - off) % 26 + 'A';
plain += temp, key += temp;
}
cout << plain << endl;
return 0;
}
D - Lost in Translation
E - Red Rover(暴力)
给出一个字符串 ,若能把其中一个子串作为marco串,把原串缩成若干marco串和其他字符,总长度将变成marco串数量+其他字符的总数量。问这个原串的最小总长度是多少。
思路:枚举每一个子串作为marco串,对原串检查即可。
#include <bits/stdc++.h>
using namespace std;
string s;
bool judge(int idx, int st, int ed)
{
for(int i = idx ; i < idx + (ed - st + 1); i++)
{
if(s[i] != s[st + i - idx]) return false;
}
return true;
}
int main()
{
cin >> s;
int minn = s.size();
for(int st = 0; st < s.size(); st++)
{
for(int ed = st; ed < s.size(); ed++)
{
int idx = 0, cnt = 0;
while(idx < s.size())
{
if(judge(idx, st, ed)) idx = idx + (ed - st + 1), cnt++;
else idx++;
}
minn = min(minn, (int)s.size() - cnt * (ed - st + 1 - 1) + ed - st + 1);
}
}
printf("%d\n", minn);
return 0;
}
F - Removal Game (dp)
题意:给出一个序列 ,每次选择一个a[k]删除,这个操作的花费是它左边第一个,右边第一个,两个未删除的元素的gcd。整个数组可看做一个环,即最初未删除任何元素时,a[n-1]的右边第一个数字为a[0]。
思路:dp[i][j]:a[i]到a[j]之间只剩下a[i]和a[j]的最小花费。最后的答案显然是 ,因为题意是一个环,所以可以从a[j]再绕到a[i]。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
const int INF = 0x3f3f3f3f;
int a[maxn];
int dp[maxn][maxn];
int main()
{
int n;
while(~scanf("%d", &n))
{
if(n == 0) break;
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
memset(dp, INF, sizeof(dp));
for(int len = 2; len <= n; len++)
{
for(int st = 0, ed = len - 1; st < n; st++, ed = (ed + 1) % n)
{
if(len == 2)
{
dp[st][ed] = 0;
}
else for(int k = (st + 1) % n; k != ed; k = (k + 1) % n)
{
dp[st][ed] = min(dp[st][ed], dp[st][k] + dp[k][ed] + __gcd(a[st], a[ed]));
}
}
}
int ans = INF;
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
ans = min(ans, dp[i][j] + dp[j][i] + __gcd(a[i], a[j]));
printf("%d\n", ans);
}
return 0;
}
G - That’s One Hanoi-ed Teacher (思维)
给出汉诺塔三个塔的状态, ,问,这是否是汉诺塔的最佳步骤中的一步,若是则输出还要几步才能完成。
#include <bits/stdc++.h>
using namespace std;
vector<int>vec[3];
int ok = 1;
long long ans = 0;
void dfs(int lv, vector<int> &a, vector<int> &b, vector<int> &c)
{
if(lv == 0) return ;
// printf("lv = %d\n", lv);
// printf("a :");for(auto o : a) cout << o << " ";puts("");
// printf("b :");for(auto o : b) cout << o << " ";puts("");
// printf("c :");for(auto o : c) cout << o << " ";puts("");
int judge1 = (a.size() != 0 && a[0] == lv);
int judge2 = (c.size() != 0 && c[0] == lv);
if(judge1 == 0 && judge2 == 0) ok = 0;
if(ok == 0) return ;
if(judge1)
{
ans += (1LL << (lv-1));
a.erase(a.begin());
dfs(lv-1, a, c, b);
}
else if(judge2)
{
c.erase(c.begin());
dfs(lv-1, b, a, c);
}
}
int main()
{
for(int k = 0; k < 3; k++)
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
vec[k].push_back(x);
}
}
dfs(vec[0].size()+vec[1].size()+vec[2].size(), vec[0], vec[1], vec[2]);
if(ok) printf("%lld\n", ans);
else puts("No");
return 0;
}
I - Waif Until Dark (网络流)
你有n个孩子,每个孩子有k个喜欢的玩具,一共有p个种类的玩具(但是有可能有玩具不属于这p类,意味着他们集成一个第p+1类)。告诉你每个孩子喜欢的k个玩具是什么,告诉你每个种类的玩具有哪些。再告诉你每个种类的玩具最多能有几个可以拿来给孩子玩。问你最多能使得多少个孩子能玩上他喜欢的玩具。
思路:最大流建图。超级源点向孩子连边,容量为1,代表每个孩子只能选一个玩具,每个孩子向自己喜欢的玩具连边,容量为1,代表每个孩子只能选一个玩具,玩具向自己的所属种类连边,容量为1,代表每个玩具贡献度为1,每个种类向超级汇点连边,容量为该种类能使用的最大数量,代表这个种类的最大贡献度。
#include <bits/stdc++.h>
using namespace std;
const int maxv = 1000 + 6;
const int INF = 0x3f3f3f3f;
struct Edge{int from, to, cap, flow;};
struct Dinic
{
int vs, st, ed;//st源点编号,ed汇点编号
vector<Edge>edges;
vector<int>G[maxv];//G[i][j]:节点i的第j条边在edges数组里的序号
bool vis[maxv];
int d[maxv];
int cur[maxv];//当前弧的下标
void addedge(int from, int to, int cap)
{
edges.push_back({from, to, cap, 0});
edges.push_back({to, from, 0, 0});
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
queue<int>que;
que.push(st);
d[st] = 0;
vis[st] = 1;
while(que.size())
{
int u = que.front();que.pop();
for(auto o : G[u])
{
Edge &e = edges[o];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[u] + 1;
que.push(e.to);
}
}
}
return vis[ed];
}
int dfs(int x, int a)//当前节点x。当前所有弧的最小残量a
{//保存每个节点x正在考虑的弧cur[x];
if(x == ed ||a == 0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
int idx = G[x][i];
Edge &e = edges[idx];
if(d[x] + 1 == d[e.to])
{
int f = dfs(e.to, min(a, e.cap - e.flow));
if(f > 0)
{
e.flow += f;
edges[idx^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
}
return flow;
}
int maxFlow(int s, int t)
{
st = s, ed = t;
int flow = 0;
while(bfs())
{
memset(cur, 0, sizeof(cur));
flow += dfs(s, INF);
}
return flow;
}
};
int vis[maxv];
int main()
{
int children, toy, category;
scanf("%d%d%d", &children, &toy, &category);// 1 2 3 4 5
Dinic dinic;
dinic.vs = 1 + children + toy + (category + 1);
dinic.st = 0, dinic.ed = dinic.vs;
for(int i = 1; i <= children; i++)
{
int k;
scanf("%d", &k);
while(k--)
{
int x;
scanf("%d", &x);
dinic.addedge(i, x + children, 1);
}
dinic.addedge(dinic.st, i, 1);
}
for(int i = 1; i <= category; i++)
{
int l;
scanf("%d", &l);
int u = children + toy + i;
while(l--)
{
int x;
scanf("%d", &x);
vis[x] = 1;
dinic.addedge(x + children, u, 1);
}
int r;
scanf("%d", &r);
dinic.addedge(u, dinic.vs, r);
}
vector<int>vec;
for(int i = 1; i <= toy; i++)
{
if(vis[i]) continue;
vec.push_back(i);
dinic.addedge(i + children, children + toy + category + 1, 1);
}
dinic.addedge(children + toy + category + 1, dinic.ed, vec.size());
printf("%d\n", dinic.maxFlow(dinic.st, dinic.ed));
return 0;
}