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

$NOIP\ 2015\ Day2$ 模拟考试 题解报告

\(NOIP\ 2015\ Day2\) 模拟考试 题解报告

得分情况

\(T1\ 100\ Pts\)

\(T2\ 90\ Pts\)

\(T3\ 15\ Pts\)

总分: \(205\ Pts\)

考试过程

太久了 快忘了...

\(T1\) 用时比较短 半个小时左右 感觉可以了写 \(T2\)

\(T2\) 一看就是 \(DP\) 写了半个小时 调了半个多小时 然后看 \(T3\)

\(T3\) 先写的只有一条的时候 然后写链 写完之后查的时候发现写错了 然后调 然后 没调过来

题解

\(T1\) 跳石头

二分答案 注意一下边界

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
const int A = 5e4 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("stone.in", "r", stdin);
	freopen("stone.out", "w", stdout);
}
/*----------------------------------------文件*/
int L, n, m, a[A], ans;
/*------------------------------------变量定义*/
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;
}
/*----------------------------------------快读*/
bool check(int x) {
	int cnt = 0, pos = 0;
	for(int i = 1; i <= n + 1; i++)
	{
		if(a[i] - a[pos] < x) cnt++;
		else pos = i;
	}
	return cnt <= m;
}
/*----------------------------------------函数*/
int main() {
	File();
	L = read(); n = read(); m = read(); a[n + 1] = L;
	for(int i = 1; i <= n; i++) a[i] = read();
	int l = 0, r = L;
	while(l <= r)
	{
		int mid = l + r >> 1;
		if(check(mid)) l = mid + 1, ans = mid;
		else r = mid - 1;
	}
	printf("%d", ans);
	return 0;
}


\(T2\) 子串

状态: \(f_{i, j, k, 0/1}\) 表示考虑 \(a\) 串前 \(i\)\(b\) 串前 \(j\) 个 已经取了 \(k\) 个串 当前位置取不取 的方案数

转移 不取的话直接继承 能取的话可以划分到上一个位置或自己再开一个串 累加方案数

注意滚动数组空间优化 注意滚动数组的清空 注意初始化

代码

/*
  Time: 6.20
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#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 mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("substring.in", "r", stdin);
	freopen("substring.out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, l, f[2][210][210][2], sum;
char a[1010], b[210];
/*------------------------------------变量定义*/
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(); l = read();
	scanf("%s%s", a + 1, b + 1);
	for(int i = 1; i <= n; i++)
	{
		memset(f[i & 1], 0, sizeof f[i & 1]);
		f[i & 1][1][1][0] = sum; if(a[i] == b[1]) f[i & 1][1][1][1] = 1, sum++;
		for(int j = 2; j <= m; j++) for(int k = 1; k <= l; k++)
		{
			f[i & 1][j][k][0] = (f[i & 1][j][k][0] + f[i & 1 ^ 1][j][k][0] + f[i & 1 ^ 1][j][k][1]) % mod;
			if(a[i] == b[j]) f[i & 1][j][k][1] = ((f[i & 1][j][k][1] + f[i & 1 ^ 1][j - 1][k - 1][0] + f[i & 1 ^ 1][j - 1][k - 1][1]) % mod + f[i & 1 ^ 1][j - 1][k][1]) % mod;
		}
	} 
	printf("%d", (f[n & 1][m][l][0] + f[n & 1][m][l][1]) % mod);
	return 0;
}


\(T3\) 运输计划

时间取决于最长的一条路径 所以题目相当于在搞掉一条边之后使最长的一条路径最短

可能从这里可以看出二分答案吧

二分最大时间 检查所有路径 对于超过二分出的时间的路径通过差分进行统计 找出所有路径的交 从交中找出最长的一条边 不难发现 这条边一定在最长的一条路径上 每一次也只需要用最长的一条路径减去这条边 判断是否在二分出的时间内 所以需要预先求出最长的路径的长度 且需要多次用到点对之间的 \(LCA\) 可以提前预处理

代码

/*
  Time: 6.23
  Worker: Blank_space
  Source: P2680 [NOIP2015 提高组] 运输计划
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define mid (l + r >> 1)
#define Max(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(".in", "r", stdin);
	freopen(".out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, dis[B], dep[B], top[B], fa[B], siz[B], son[B], max, c[B], d[B], cnt, _max, ans;
struct node {int u, v, lca, w;} a[B];
struct edge {int v, w, 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, int w) {e[++ecnt] = (edge){v, w, 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, w = e[i].w; if(v == pre) continue;
		d[v] = w; dis[v] = dis[u] + w; dfs1(v, u); siz[u] += siz[v];
		if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
	}
}
void dfs2(int u, int tp) {
	top[u] = tp; if(son[u]) dfs2(son[u], tp);
	for(int i = head[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v)
		if(v != fa[u] && v != son[u]) 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 dfs(int u, int pre) {
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].v != pre) dfs(e[i].v, u), c[u] += c[e[i].v];
	if(c[u] == cnt && d[u] > _max) _max = d[u];
}
bool check(int x) {
	memset(c, 0, sizeof c); cnt = _max = 0;
	for(int i = 1; i <= m; i++)
		if(a[i].w > x) c[a[i].u]++, c[a[i].v]++, c[a[i].lca] -= 2, cnt++;
	dfs(1, 0); return max - _max <= x;
}
/*----------------------------------------函数*/
int main() {
	n = read(); m = read();
	for(int i = 1; i < n; i++)
	{
		int x = read(), y = read(), z = read();
		add_edge(x, y, z); add_edge(y, x, z);
	}
	dfs1(1, 0); dfs2(1, 1);
	for(int i = 1; i <= m; i++)
	{
		int x = read(), y = read(), z = LCA(x, y), k = dis[x] + dis[y] - 2 * dis[z];
		a[i] = (node){x, y, z, k}; max = Max(max, k);
	}
	int l = 0, r = max;
	while(l <= r)
		if(check(mid)) ans = mid, r = mid - 1;
		else l = mid + 1;
	printf("%d", ans);
	return 0;
}

很罕见的调都没调 写完一发 \(A\)

posted @ 2021-06-23 15:11  Blank_space  阅读(41)  评论(1编辑  收藏  举报
// // // // // // //