模拟赛小结:2017 China Collegiate Programming Contest Final (CCPC-Final 2017)
比赛链接:传送门
前期大顺风,2:30金区中游。后期开题乏力,掉到银尾。4:59绝杀I,但罚时太高卡在银首。
Problem A - Dogs and Cages 00:09:45 (+) Solved by Dancepted
算了半天发现就是n-1,被队友喷死,差点气哭。
Problem E - Evil Forest 00:16:54 (+) Solved by xk
xk大喊签到,就过了。
代码:
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
int main() {
fast;
int T, kase = 1;
cin >> T;
while (T--) {
int n;
cin >> n;
int ans = 0;
for(int i = 0; i < n; i++)
{
int x;
cin >> x;
ans += x + upperdiv(x, 10);
}
cout << "Case #" << (kase++) << ": " << ans << endl;
}
return 0;
}
Problem C - Rich Game 00:32:42 (+) Solved by xk
xk又喊了一声签到!
代码:
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
int main() {
fast;
int T, kase = 1;
cin >> T;
while (T--) {
int x, y, k;
cin >> x >> y >> k;
int money = 0, ans = 0;
if(x > y) ans = k;
else
{
for(int i = 0; i < k; i++)
{
if(money + 9 * x >= 11 * y) {
money += 9 * x - 11 * y;
ans++;
}
else {
money += 11 * x;
}
}
}
cout << "Case #" << (kase++) << ": " << ans << endl;
}
return 0;
}
Problem K - Knightmare 00:46:33 (+) Solved by Dancepted
步数较少的时候可以往回走,把没走过的地方填上,步数增长到一定程度时,答案差不多会均匀增长。
我猜测是小数据打表,大数据是个公式之类的。
开完A趁电脑没人就打了个表,发现和我的猜测是一致的,果断交了一发就过了。
代码:
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <stdio.h>
#include <utility>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 1005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef __int128 ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
const int ans[10] = {1, 9, 41, 109, 205, 325};
int main() {
int T; cin >> T;
int kase = 1;
while (T--) {
ll n; read(n);
printf("Case #%d: ", kase++);
if (n <= 5) {
write(ans[n]);
}
else {
ll res = 14 * n * n - 6 * n + 5;
write(res);
}
putchar('\n');
}
return 0;
}
Problem J - Subway Chasing 01:42:00 (+) Solved by xk & lh
好像是差分约束什么的。图论这种事相信队友就完了。
代码:
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
const int maxn = 2000 + 5;
struct edge
{
int v, l;
};
ll dis[maxn];
int cnt[maxn];
bool inq[maxn];
vector<edge> g[maxn];
void addedge(int u, int v, int l)
{
g[u].push_back(edge{v, l});
// g[v].push_back(edge{u, l});
}
int n, m, x;
bool spfa()
{
queue<int> q;
dis[1] = 0;
q.push(1);
cnt[1] = inq[1] = 1;
while(!q.empty())
{
int u = q.front();
inq[u] = 0;
q.pop();
for(auto &e : g[u])
{
if(dis[e.v] > dis[u] + e.l)
{
dis[e.v] = dis[u] + e.l;
if(!inq[e.v]) {
cnt[e.v]++;
if(cnt[e.v] >= n) return false;
q.push(e.v);
inq[e.v] = 1;
}
}
}
}
return true;
}
int main()
{
fast;
int T, kase = 1;
cin >> T;
while (T--)
{
cin >> n >> m >> x;
for(int i = 1; i <= n; i++)
{
g[i].clear();
dis[i] = 1e18;
cnt[i] = inq[i] = 0;
}
for(int i = 1; i < n; i++)
{
addedge(i+1, i, -1);
addedge(i, i+1, 2e9);
}
for(int i = 0; i < m; i++)
{
int a, b, c, d;
cin >> a >> b >> c >> d;
if(a == b)
{
if(c == d)
{
addedge(a, c, x);
addedge(c, a, -x);
}
else
{
addedge(a, c, x - 1);
addedge(d, a, -x - 1);
}
}
else
{
if(c == d)
{
addedge(b, c, x - 1);
addedge(c, a, -x - 1);
}
else
{
addedge(b, c, x - 1);
addedge(d, a, -x - 1);
}
}
}
cout << "Case #" << (kase++);
if(!spfa()) cout << " IMPOSSIBLE\n";
else {
for(int i = 2; i <= n; i++)
cout << ' ' << dis[i] - dis[i - 1];
cout << endl;
}
}
return 0;
}
Problem G - Alice’s Stamps 02:24:14 (-2) Solved by Dancepted (dp)
上机的时候思路有乱,调出来之后交上去因为N开大了MLE返回CE,贡献了两发罚时。
dfs枚举当前搜索过的最右端点和剩下的k的数量,记忆化一下,状态数最多就$O(n^{2})$。
HDU的T组数据比较玄学,差点没敢交。
代码:$O(n^{2})$
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 2005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x)
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
struct Node{
int l, r;
bool operator < (const Node& x) const {
if (r == x.r) {
return l < x.l;
}
return r < x.r;
}
};
int n, m, k;
vector<Node> ns, ns1;
int ans = 0;
int f[N][N];
int dfs(int id, int r, int cnt, int resk) {
if (f[r][resk]) {
return f[r][resk];
}
if (resk == 0) {
return 0;
}
if (id >= sz(ns)) {
return 0;
}
int tmp = dfs(id+1, r, cnt, resk);
tmp = max(tmp, ns[id].r - max(ns[id].l-1, r) + dfs(id+1, ns[id].r, cnt + ns[id].r - max(ns[id].l-1, r), resk-1));
ans = max(ans, cnt + tmp);
return f[r][resk] = tmp;
}
bool ok[N];
int l[N], r[N];
int main() {
int T, kase = 1;
cin >> T;
while (T--) {
ns.clear(), ns1.clear();
read(n, m, k);
for (int i = 1; i <= m; i++) {
read(l[i], r[i]);
ok[i] = true;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) if (i != j) {
if (l[i] < l[j] && r[j] <= r[i]) {
ok[j] = false;
}
}
}
for (int i = 1; i <= m; i++) if (ok[i]) {
ns.push_back(Node{l[i], r[i]});
}
sort(ns.begin(), ns.end());
// init();
ans = 0;
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= k; j++) {
f[i][j] = 0;
}
}
dfs(0, 0, 0, k);
printf("Case #%d: %d\n", kase++, ans);
}
return 0;
}
题解的做法是一个很好写的dp:
$f_{i, j}$表示最右边的覆盖点是i的情况下,用了j个集合的最大覆盖长度。
代码:$O(n^{2})$
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 2005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
int mxr[N];
int f[N][N];
int main() {
int T; cin >> T;
for (int kase = 1; kase <= T; kase++) {
int n, m, k; read(n, m, k);
memset(mxr, 0, (n+1) * sizeof(int));
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= k; j++) {
f[i][j] = 0;
}
}
for (int i = 1; i <= m; i++) {
int l, r; read(l, r);
mxr[l] = max(mxr[l], r);
}
int ans = 0, r = 0;
for (int i = 1; i <= n; i++) {
r = max(mxr[i], r);
for (int j = 0; j <= k; j++) {
f[i][j] = max(f[i][j], f[i-1][j]);
ans = max(ans, f[i][j]);
if (j+1 <= k)
f[r][j+1] = max(f[r][j+1], f[i-1][j] + r - i + 1),
ans = max(ans, f[r][j+1]);
}
}
printf("Case #%d: %d\n", kase, ans);
}
return 0;
}
Problem I - Inkopolis 04:59:59 (-3) Solved by Dancepted & xk
中午还在看的基环树下午就用到了。
先考虑树上的情况。会影响答案的部分只有修改颜色之前的颜色$color_{pre}$,和之后的颜色$color_{now}$两种。看是否会新增、删除color region,或者合并、分割原来的color region。
再考虑环上的情况。同上。特别地:如果整个环都是同一种颜色,修改了颜色不会分割原来的color region;如果整个环除了修改的边都是$color_{now}$,则修改颜色不会合并color region。
计算节日开始前各街道的颜色,可以模仿修改的操作,一条条边加入就行了。
实现的时候先把环扣出来,统计一下环各颜色的边数量。用个map保存每个点相邻的各颜色的数量。再用map保存每条边的颜色。
然后扫一遍所有的边先计算初始情况下的region的数量sum,然后一次次修改边的颜色,更新sum就好了。
代码:O(nlogn)
#include <iostream>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 200005
#define M 200005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
/** fast read **/
template <typename T>
inline void read(T &x) {
x = 0; T fg = 1; char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') fg = -1;
ch = getchar();
}
while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
do{++len; c[len] = x%10 + '0';} while (x /= 10);
for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
int tot;
int head[N], nxt[N<<1], ver[N<<1], col[N<<1];
void addEdge(int u, int v, int c) {
nxt[tot] = head[u], ver[tot] = v, col[tot] = c, head[u] = tot++;
}
int iscir[N], cirlen;
bool vis[N];
int getCir(int u, int fa, int& rt) {
vis[u] = true;
for (int i = head[u]; i != -1; i = nxt[i]) {
int v = ver[i];
if (v == fa) continue;
if (vis[v]) {
rt = v;
iscir[u] = 1;
cirlen++;
return 1;
}
else {
int tmpcir = getCir(v, u, rt);
if (tmpcir) {
iscir[u] = tmpcir;
cirlen++;
return u != rt;
}
}
}
return 0;
}
int cnt[N];
int sum;
map<int, int> mp[N];
map<pair<int,int>, int> uv_col;
void update(int u, int v, int ccur, bool ifprint) {
if (u > v) swap(u, v);
int cpre = uv_col[mp(u, v)];
if (cpre == ccur) {
if (ifprint)
printf("%d\n", sum);
return;
}
if (!iscir[u] || !iscir[v]) {
//on tree
if (mp[u][cpre] >= 2 && mp[v][cpre] >= 2) {
sum++;
}
if (mp[u][cpre] == 1 && mp[v][cpre] == 1) {
sum--;
}
if (mp[u][ccur] && mp[v][ccur]) {
sum--;
}
if (!mp[u][ccur] && !mp[v][ccur]) {
sum++;
}
}
else {
//on circle
if (mp[u][cpre] >= 2 && mp[v][cpre] >= 2) {
if (cnt[cpre] != cirlen)
sum++;
}
if (mp[u][cpre] == 1 && mp[v][cpre] == 1) {
sum--;
}
if (mp[u][ccur] && mp[v][ccur]) {
if (cnt[ccur] != cirlen-1)
sum--;
}
if (!mp[u][ccur] && !mp[v][ccur]) {
sum++;
}
if (cpre != -1)
cnt[cpre]--;
cnt[ccur]++;
}
uv_col[mp(u, v)] = ccur;
if (cpre != -1) {
mp[u][cpre]--;
mp[v][cpre]--;
}
mp[u][ccur]++;
mp[v][ccur]++;
if (ifprint)
printf("%d\n", sum);
}
int main() {
int T;
cin >> T;
for (int kase = 1; kase <= T; kase++) {
int n, m; read(n, m);
// init
uv_col.clear();
for (int i = 1; i <= n; i++) {
mp[i].clear();
}
tot = 0;
memset(head, -1, (n+1) * sizeof(int));
// input and count colors on every edge
for (int i = 1; i <= n; i++) {
int u, v, c; read(u, v, c);
addEdge(u, v, c);
addEdge(v, u, c);
if (u > v)
swap(u, v);
uv_col[mp(u, v)] = -1;
// mp[u][c]++; mp[v][c]++;
}
// get circle
int rt = -1;
memset(vis, false, (n+1) * sizeof(bool));
memset(iscir, 0, (n+1) * sizeof(int));
cirlen = 0;
getCir(1, -1, rt);
// count colors on circle
memset(cnt, 0, (n+1) * sizeof(int));
sum = 0;
for (int i = 0; i < n; i++) {
int u = ver[i<<1], v = ver[i<<1|1], ccur = col[i<<1];
update(u, v, ccur, false);
}
printf("Case #%d:\n", kase);
for (int i = 1; i <= m; i++) {
int u, v, ccur; read(u, v, ccur);
update(u, v, ccur, true);
}
}
return 0;
}
/*
11111
5 10
1 5 1
2 5 1
3 5 1
4 5 1
1 2 1
1 2 1
2
4 4
1 2 1
2 3 1
3 4 1
4 1 1
1 2 2
3 4 2
2 3 2
4 1 4
4 3
4 2 4
2 3 3
3 4 2
1 4 1
3 4 2
2 3 4
3 4 3
*/
总结:
本场能绝杀还是有点运气成分在的,而且现场赛的话最后几分钟可能就交不上题了也可能。不过绝杀也不影响苟在银牌,问题不大。
然后最近的几场好像都是我在贡献罚时,感觉码力出现了一些小小的问题。这两天要小心一点。
然后还有两周可能就要退役了,模拟赛还没有进过金区感觉很难受啊,打成这个样子还怎么冲金啊qaq。