$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\) 小凯的疑惑
/*
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
没思路
暴力...
强过样例
*/