$NOIP\ 2016\ Day1$ 模拟考试 题解报告
\(NOIP\ 2016\ Day1\) 模拟考试 题解报告
得分情况
\(T1\) \(85\ Pts\)
\(T2\) \(15\ Pts\)
\(T3\) \(100\ Pts\)
总分: \(200\ Pts\)
考试过程
看完 \(T1\) 半个小时写完了 \(T2\) 不可做 去看 \(T3\) 然后写 + 调两个小时 回头写 \(T2\) 没写完 过了编译直接交了
题解
\(T1\) 玩具谜题
模拟
应该是没有和我写的一样的 比较短 要注意一下细节 想到了取模 没想到会加爆
代码
/*
Time: 6.13
Worker: Blank_space
Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
/*--------------------------------------头文件*/
const int B = 1e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
freopen("toy.in", "r", stdin);
freopen("toy.out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, to[B], pos;
std::string na[B];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
/*----------------------------------------函数*/
int main() {
// File();
n = read(); m = read(); pos = 1;
for(int i = 1; i <= n; i++) {to[i] = read(); if(!to[i]) to[i] = -1; std::cin >> na[i];}
for(int i = 1; i <= m; i++)
{
int x = read(), y = read(); if(!x) x = -1;
int z = x * to[pos]; while(~z && pos <= y) pos += n;
pos -= z * y; if(pos > n) pos %= n;
}
std::cout << na[pos];
return 0;
}
\(T2\) 天天爱跑步
时间不够... 只想到了 \(O(n^2)\) 的做法 样例都没跑 过了编译直接交了 后来发现不分测试点的话能有 \(25\ Pts\) 分了测试点反而挂了 \(10\ Pts\)
\(25\ Pts\) 暴力
起点和终点求 \(LCA\) 向上暴跳 开桶记录答案即可
void up(int x, int y) {
_cnt = 0;
while(x != y) _c[x][_cnt++]++, x = fa[x];
_c[x][_cnt]++;
}
void down(int x, int y) {
_cnt += dep[x] - dep[y];
while(x != y) _c[x][_cnt--]++, x = fa[x];
}
void work1() {
dfs(1, 0); dfs2(1, 1);
for(int i = 1; i <= m; i++)
{
int lca = LCA(s[i], t[i]);
up(s[i], lca); down(t[i], lca);
}
for(int i = 1; i <= n; i++) ans[i] = _c[i][w[i]];
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
\(15\ Pts\) 链
从一个点出发只有向左或向右两种情况 对于在 \(j\) 点的观察员 有
为分别向右向左
类似差分的思想用桶统计贡献 从左向右扫一遍 桶中加入该点向右出发的路径条数 按照上面统计合法的节点个数 在左侧的能到达这个点位置的桶\(--\) 再从右向左扫一遍 即为答案
for(int i = 1; i <= m; i++) s[i] = read(), t[i] = read(), cs[s[i]].push_back(t[i]), ct[t[i]].push_back(s[i]);
void work2() {
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < cs[i].size(); j++) if(i <= cs[i][j]) o[i]++;
if(i > w[i]) ans[i] += o[i - w[i]];
for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] <= i) o[ct[i][j]]--;
}
memset(o, 0, sizeof o);
for(int i = n; i >= 1; i--)
{
for(int j = 0; j < cs[i].size(); j++) if(i > cs[i][j]) o[i]++;
if(i + w[i] <= n) ans[i] += o[i + w[i]];
for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] > i) o[ct[i][j]]--;
}
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
\(20\ Pts\) 所有起点都为 \(1\)
直接以 \(1\) 为根 当一个点 \(i\) 的 \(w_i = dep_i\) (这里我的深度是从一开始的 实际代码中要减一)时 这个点能观察到的就是以该点为根的子树中终点的个数 否则为 \(0\)
void dfs3(int u, int pre) {
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v; if(v == pre) continue;
dfs3(v, u); _siz[u] += _siz[v];
}
if(w[u] == dep[u] - 1) ans[u] = _siz[u];
}
void work3() {
for(int i = 1; i <= m; i++) _siz[t[i]]++;
dfs3(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
\(20\ Pts\) 所有终点都为 \(1\)
直接 \(1\) 为根 当一个点 \(i\) 有 \(w_i + dep_i = l\) (其中 \(l\) 为链长) 时 有贡献 \(dfs\) 开桶记录 求增量即为答案
void dfs4(int u, int pre) {
int k = o[w[u] + dep[u] - 1]; o[dep[u] - 1] += oo[u];
for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs4(e[i].v, u);
ans[u] += o[w[u] + dep[u] - 1] - k;
}
void work4() {
for(int i = 1; i <= m; i++) oo[s[i]]++;
dfs4(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
\(20\ Pts\) 正解
每一条路径可以分为两部分 一部分向上另一部分向下 向上的时候对于 \(i\) 当 \(dep_i + w_i = dep_s\) 时 能观察到 向下的时候 对于 \(i\) 当 \(dep_i + w_i = dep_t - l + 1\) (\(l\) 仍为链长) 时 能观察到 求 \(LCA\) 进行树上差分
但是这个题卡了一手 \(vector\) 导致不开 \(O_2\) 过不去...
代码
void dfs(int u, int pre) {
int k = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1];
for(int i = 0; i < cs[u].size(); i++) o[cs[u][i]]++;
for(int i = 0; i < ct[u].size(); i++) oo[ct[u][i]]++;
for(int i = 0; i < ks[u].size(); i++) o[ks[u][i]]--;
for(int i = 0; i < kt[u].size(); i++) oo[kt[u][i]]--;
for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs(e[i].v, u);
ans[u] = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1] - k;
}
void work() {
for(int i = 1; i <= m; i++)
{
int lca = LCA(s[i], t[i]);
l[i] = dep[s[i]] + dep[t[i]] - 2 * dep[lca];
cs[s[i]].push_back(dep[s[i]] - 1);
ct[t[i]].push_back(dep[t[i]] - 1 - l[i]);
ks[lca].push_back(dep[s[i]] - 1);
kt[fa[lca]].push_back(dep[t[i]] - 1 - l[i]);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
完整代码
/*
Time: 6.14
Worker: Blank_space
Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int B = 3e5 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
freopen("running.in", "r", stdin);
freopen("running.out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, w[B], s[B], t[B], vis[B], ans[B], siz[B], fa[B], son[B], top[B], dfn[B], dep[B], cnt, _c[1000][1000], _cnt;
int o[B], oo[B], _siz[B], l[B];
std::vector <int> cs[B], ct[B], ks[B], kt[B];
struct edge {int v, nxt;} e[B << 1];
int head[B], ecnt;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v) {e[++ecnt] = (edge){v, head[u]}; head[u] = ecnt;}
void dfs1(int u, int pre) {
siz[u] = 1; fa[u] = pre; dep[u] = dep[pre] + 1;
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v; if(v == pre) continue;
dfs1(v, u); siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp; dfn[u] = ++cnt;
if(!son[u]) return ; dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v; if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int LCA(int x, int y) {
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) Swap(x, y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) Swap(x, y);
return x;
}
void up(int x, int y) {
_cnt = 0;
while(x != y) _c[x][_cnt++]++, x = fa[x];
_c[x][_cnt]++;
}
void down(int x, int y) {
_cnt += dep[x] - dep[y];
while(x != y) _c[x][_cnt--]++, x = fa[x];
}
void work1() {
for(int i = 1; i <= m; i++)
{
int lca = LCA(s[i], t[i]);
up(s[i], lca); down(t[i], lca);
}
for(int i = 1; i <= n; i++) ans[i] = _c[i][w[i]];
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
void work2() {
for(int i = 1; i <= m; i++) cs[s[i]].push_back(t[i]), ct[t[i]].push_back(s[i]);
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < cs[i].size(); j++) if(i <= cs[i][j]) o[i]++;
if(i > w[i]) ans[i] += o[i - w[i]];
for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] <= i) o[ct[i][j]]--;
}
memset(o, 0, sizeof o);
for(int i = n; i >= 1; i--)
{
for(int j = 0; j < cs[i].size(); j++) if(i > cs[i][j]) o[i]++;
if(i + w[i] <= n) ans[i] += o[i + w[i]];
for(int j = 0; j < ct[i].size(); j++) if(ct[i][j] > i) o[ct[i][j]]--;
}
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
void dfs3(int u, int pre) {
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v; if(v == pre) continue;
dfs3(v, u); _siz[u] += _siz[v];
}
if(w[u] == dep[u] - 1) ans[u] = _siz[u];
}
void work3() {
for(int i = 1; i <= m; i++) _siz[t[i]]++;
dfs3(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
void dfs4(int u, int pre) {
int k = o[w[u] + dep[u] - 1]; o[dep[u] - 1] += oo[u];
for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs4(e[i].v, u);
ans[u] += o[w[u] + dep[u] - 1] - k;
}
void work4() {
for(int i = 1; i <= m; i++) oo[s[i]]++;
dfs4(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
void dfs(int u, int pre) {
int k = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1];
for(int i = 0; i < cs[u].size(); i++) o[cs[u][i]]++;
for(int i = 0; i < ct[u].size(); i++) oo[ct[u][i]]++;
for(int i = 0; i < ks[u].size(); i++) o[ks[u][i]]--;
for(int i = 0; i < kt[u].size(); i++) oo[kt[u][i]]--;
for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs(e[i].v, u);
ans[u] = o[w[u] + dep[u] - 1] + oo[dep[u] - w[u] - 1] - k;
}
void work() {
for(int i = 1; i <= m; i++)
{
int lca = LCA(s[i], t[i]);
l[i] = dep[s[i]] + dep[t[i]] - 2 * dep[lca];
cs[s[i]].push_back(dep[s[i]] - 1);
ct[t[i]].push_back(dep[t[i]] - 1 - l[i]);
ks[lca].push_back(dep[s[i]] - 1);
kt[fa[lca]].push_back(dep[t[i]] - 1 - l[i]);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) printf("%d ", ans[i]);
}
/*----------------------------------------函数*/
int main() {
File();
n = read(); m = read();
for(int i = 1; i < n; i++)
{
int x = read(), y = read();
add_edge(x, y); add_edge(y, x);
}
for(int i = 1; i <= n; i++) w[i] = read();
for(int i = 1; i <= m; i++) s[i] = read(), t[i] = read();
dfs1(1, 0); dfs2(1, 1);
if(n <= 1000) work1();
else if(n == 99994) work2();
else if(n == 99995) work3();
else if(n == 99996) work4();
else work();
return 0;
}
\(T3\) 换教室
做过
点比较少 先跑全源最短路 然后 \(DP\)
代码
/*
Time: 6.13
Worker: Blank_space
Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define Min(x, y) ((x) < (y) ? (x) : (y))
/*--------------------------------------头文件*/
const double INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
freopen("classroom10.in", "r", stdin);
// freopen("classroom.out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, v, e, dis[310][310], c[2021], d[2021];
double f[2021][2021][2], ans = INF, p[2021];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
/*----------------------------------------函数*/
int main() {
File();
n = read(); m = read(); v = read(); e = read();
memset(dis, 63, sizeof dis);
for(int i = 1; i <= n; i++) c[i] = read();
for(int i = 1; i <= n; i++) d[i] = read();
for(int i = 1; i <= n; i++) scanf("%lf", &p[i]);
for(int i = 1; i <= e; i++)
{
int x = read(), y = read(), z = read();
dis[x][y] = dis[y][x] = Min(dis[x][y], z);
}
for(int l = 1; l <= v; l++) for(int i = 1; i <= v; i++) for(int j = 1; j <= v; j++) dis[i][j] = Min(dis[i][j], dis[i][l] + dis[l][j]);
for (int i = 1; i <= v; i++) dis[i][i] = dis[i][0] = dis[0][i] = 0;
for(int i = 0; i <= n; i++) for(int j = 0; j <= m; j++) f[i][j][0] = f[i][j][1] = INF;
f[1][0][0] = f[1][1][1] = 0;
for(int i = 2; i <= n; i++)
{
f[i][0][0] = f[i - 1][0][0] + dis[c[i - 1]][c[i]];
for(int j = 1; j <= Min(i, m); j++)
f[i][j][0] = Min(f[i][j][0], Min(f[i - 1][j][0] + dis[c[i - 1]][c[i]], f[i - 1][j][1] + p[i - 1] * dis[d[i - 1]][c[i]] + (1 - p[i - 1]) * dis[c[i - 1]][c[i]])),
f[i][j][1] = Min(f[i][j][1], Min(f[i - 1][j - 1][0] + p[i] * dis[c[i - 1]][d[i]] + (1 - p[i]) * dis[c[i - 1]][c[i]], f[i - 1][j - 1][1] + p[i - 1] * p[i] * dis[d[i - 1]][d[i]] + (1 - p[i - 1]) * p[i] * dis[c[i - 1]][d[i]] + p[i - 1] * (1 - p[i]) * dis[d[i - 1]][c[i]] + (1 - p[i - 1]) * (1 - p[i]) * dis[c[i - 1]][c[i]]));
}
for(int i = 0; i <= m; i++) ans = Min(ans, Min(f[n][i][0], f[n][i][1]));
printf("%.2lf", ans);
return 0;
}