// // // // // // // // // // // // // //

$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\) 点的观察员 有

\[s = j - w_j\\ s = j + w_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;
}

posted @ 2021-06-14 11:50  Blank_space  阅读(48)  评论(0编辑  收藏  举报
// // // // // // //