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

$NOIP\ 2017\ Day1$ 模拟考试 题解报告

\(NOIP\ 2017\ Day1\) 模拟考试 题解报告

得分情况

\(T1\) \(100\ Pts\)

\(T2\) \(100\ Pts\)

\(T3\) \(10\ Pts\)

总分: \(210\ Pts\)

考试过程

\(T1\) 背结论

\(T2\) 一开始半个小时比较乱 去看了一下 \(T3\) 捣鼓半个小时 感觉是 \(dp\) 但是没什么思路 又回过头来看 \(T2\) 理清思路 写了半个小时 又造样例自测 感觉没问题去写 \(T3\) 发现只会 \(k = 0\) 的情况 写了个比较傻的 \(dp\) 然后想别的 不会写 所以写了个暴力 又怕 \(dp\) 错 分了一下测试点 然后 \(dp\) 的那一部分过了 暴力的挂了...

题解

\(T1\) 小凯的疑惑

\[ans = x \times y - x - y \]

/*
  Time: 6.6
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#define int long long
/*--------------------------------------头文件*/
inline void File() {
	freopen("math.in", "r", stdin);
	freopen("math.out", "w", stdout);
}
/*----------------------------------------文件*/

/*------------------------------------变量定义*/
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;
}
/*----------------------------------------快读*/

/*----------------------------------------函数*/
signed main() {
	File(); 
	int x = read(), y = read();
	printf("%lld", x * y - x - y);
	return 0;
}

\(T2\) 时间复杂度

大模拟 没什么好说的

/*
  Time: 6.6
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("complexity.in", "r", stdin);
	freopen("complexity.out", "w", stdout);
}
/*----------------------------------------文件*/
int T, n, st[A], cnt, cnt1, cnt2, O, t, z[110];
std::map <std::string, bool> vis;
std::string s, op, s1, s2, s3, pos[110];
bool ERR, NO, YES, p;
/*------------------------------------变量定义*/
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 work1(int i) {//cnt2 无效循环 cnt1 有效循环 
	std::cin >> s1 >> s2 >> s3; pos[i] = s1;
	if(vis[s1]) {ERR = 1; return ;} vis[s1] = 1;
	if(cnt2) st[++cnt] = i, cnt2++;
	else if(s3[0] == 'n')
	{
		if(s2 < s3) O++, z[++cnt1] = 2, p = 1;//O(n)
		else z[++cnt1] = 1;
		if(O == t) YES = 1;
		if(O > t) NO = 1;
		st[++cnt] = i;
	}
	else if(s2[0] == 'n')
	{
		if(s1[0] != 'n') cnt2++, st[++cnt] = i;
	}
	else
	{
		int a = 0, b = 0;
		for(int j = 0; j < s2.length(); j++) a = a * 10 + s2[j] - 48;
		for(int j = 0; j < s3.length(); j++) b = b * 10 + s3[j] - 48;
		if(a <= b) z[++cnt1] = 1; else cnt2++; st[++cnt] = i;
	}
}
void work2() {
	if(cnt2) {vis[pos[st[cnt--]]] = 0; cnt2--; return ;}
	if(!cnt) {ERR = 1; return ;}
	vis[pos[st[cnt--]]] = 0; if(z[cnt1--] == 2) O--;
}
void clear() {
	cnt1 = cnt2 = ERR = NO = YES = O = t = p = 0;
	for(int i = 1; i <= n; i++) vis[pos[i]] = 0, pos[i].clear();
}
void work() {
	clear();
	n = read(); std::cin >> s; if(n & 1) ERR = 1;
	if(s[2] == '1') t = 0;
	else for(int j = 4; j < s.length() - 1; j++) t = t * 10 + s[j] - 48;
	for(int i = 1; i <= n; i++)
	{
		std::cin >> op;
		if(op[0] == 'F') work1(i);
		else work2();
	}
	if(!p && !t) YES = 1;
	if(cnt1 || cnt2 || ERR) puts("ERR");
	else if(NO) puts("No");
	else if(!YES) puts("No");
	else puts("Yes");
}
/*----------------------------------------函数*/
int main() {
	File();
	T = read(); while(T--) work();
	return 0;
}
/*
五点 无进展 
最后写 
8
2 O(1)
F i 1 1
E
2 O(n^1)
F x 1 n
E
1 O(1)
F x 1 n
4 O(n^2)
F x 5 n
F y 10 n
E
E
4 O(n^2)
F x 9 n
E
F y 2 n
E
4 O(n^1)
F x 9 n
F y n 4
E
E
4 O(1)
F y n 4
F x 9 n
E
E
4 O(n^2)
F x 1 n
F x 1 10
E
E

样例过了 跑路了 
*/

\(T3\) 逛公园

首先题目给人一种 \(dp\) 的感觉 然后看到 \(K\) 的范围 必然是一个和 \(K\) 有关的 \(dp\)

状态 设 \(f_{u, x}\) 表示 到达 \(u\) 点时距 \(n\) 点距离为 \(x\) 的路径条数

\(dis_u\) 表示 \(1\) 号点到 \(u\) 点的最短路 \(w_{u, v}\) 表示两点之间的边权

转移 \(f_{u, x} = \sum f_{v, x + dis_u - dis_v - w_{u, v}}\)

\(y = x + dis_u - dis_v - w_{u, v}\) 在转移过程中 \(y < 0\)\(y > x\) 一定是不合法的(考虑状态就可以知道) 再考虑 \(-1\) 的情况 容易发现 当路径有无数条时候 一个状态一定会被多次经过 也就是第二次到达 \(u\) 点的时候 \(u\) 点的 \(x\) 值没有发生改变 那么必然有一种方式再次回到 \(u\) 点使得 \(x\) 值仍不变(其实就是 \(0\) 环) 记录重复即可

初始状态 \(f_{n, x}\)\(x\) 需要枚举

代码

/*
  Time: 6.6
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<queue>
#define p1 first
#define p2 second
#define mk std::make_pair
/*--------------------------------------头文件*/
const int A = 2e3 + 7;
const int B = 1e5 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("park.in", "r", stdin);
	freopen("park.out", "w", stdout);
}
/*----------------------------------------文件*/
int T, n, m, k, mod, dis[B], vis[B][60], f[B][60], ans;
struct edge {int v, w, nxt;} e[B << 1], g[B << 1];
int head[B], ecnt, ghead[B], gcnt;
std::priority_queue <std::pair <int, int> > q;
bool flag, _d[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;
}
/*----------------------------------------快读*/
void add_edge(int u, int v, int w) {
	e[++ecnt] = (edge){v, w, head[u]}; head[u] = ecnt;
	g[++gcnt] = (edge){u, w, ghead[v]}; ghead[v] = gcnt;
}
void dijk() {
	memset(dis, 63, sizeof dis);
	dis[1] = 0; q.push(mk(-dis[1], 1));
	memset(_d, 0, sizeof _d);
	while(!q.empty())
	{
		int u = q.top().p2; q.pop(); if(_d[u]) continue; _d[u] = 1;
		for(int i = head[u]; i; i = e[i].nxt)
		{
			int v = e[i].v, w = e[i].w;
			if(dis[v] > dis[u] + w) dis[v] = dis[u] + w, q.push(mk(-dis[v], v));
		}
	}
}
void dfs(int u, int x) {
	if(vis[u][x] == 1 || flag) {flag = 1; return ;}
	if(vis[u][x] == 2) return ; vis[u][x] = 1;
	for(int i = ghead[u]; i; i = g[i].nxt)
	{
		int v = g[i].v, w = g[i].w, y = x + dis[u] - dis[v] - w;
		if(y < 0 || y > x) continue; dfs(v, y);
		f[u][x] = (f[u][x] + f[v][y]) % mod;
	}
	vis[u][x] = 2;
}
void work() {
	n = read(); m = read(); k = read(); mod = read(); ans = 0; flag = 0;
	memset(head, 0, sizeof head); ecnt = 0; memset(ghead, 0, sizeof ghead); gcnt = 0;
	memset(f, 0, sizeof f); f[1][0] = 1; memset(vis, 0, sizeof vis);
	for(int i = 1; i <= m; i++)
	{
		int x = read(), y = read(), z = read();
		add_edge(x, y, z);
	}
	dijk();
	for(int i = 0; i <= k; i++)
	{
		dfs(n, i); ans = (ans + f[n][i]) % mod;
		if(flag) {ans = -1; break;}
	}
	printf("%d\n", ans);
}
/*----------------------------------------函数*/
int main() {
//	File();
	T = read(); while(T--) work();
	return 0;
}
/* 
先跑最短路 
求长度不超过 d + k 的路径条数 
无穷多的路径一定存在 0 环 
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0

3
5 10 0 100000
1 2 1
2 3 3
3 4 4
4 2 1
4 5 2
3 6 2
6 5 4
1 4 8
1 5 10
2 6 5
5 8 0 100000
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
1 4 1
9 15 0 10000
10 5 3
2 5 3
3 5 3
4 5 3
5 9 6
5 6 2
5 7 2
5 8 2
6 9 4
7 9 4
8 9 4
1 10 1
1 2 1
1 3 1
1 4 1

没思路 
暴力...
强过样例 
*/
posted @ 2021-06-07 22:32  Blank_space  阅读(51)  评论(0编辑  收藏  举报
// // // // // // //