我冒了严寒,去到相隔二万余里,二十多年不见的NOIP赛场去。——出自《或许我就是蒟蒻吧》
T1 math
作为Day1T1,这一题不是一般的坑……
首先设一个合法选择为
x
,则必须满足这两个条件:
1、
2、对于所有的
0≤i
并且
x−ia≥0
,有
b∤(x−ia)
。
可以发现,在第二个条件中,满足
0≤i
并且
x−ia≥0
的
i
有
而由于
a,b
互质,所以
x
不断减去
考虑在
⌊xa⌋=b−1
的范围内找答案。这种情况下如果不断地把
x
减去
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a, b;
int main() {
//freopen("math.in", "r", stdin);
//freopen("math.out", "w", stdout);
cin >> a >> b;
cout << 1ll * a * b - a - b << endl;
return 0;
}
T2 complexity
大模拟……利用一点点栈的思想……注意细节。
1、x n,
O(n)
。
2、n n,
O(1)
。
3、x y,
x<=y
则
O(1)
,否则
O(0)
(无法执行)。
4、n x,
O(0)
。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 504, INF = 0x3f3f3f3f;
char s[N][N], com[N]; int L, top, stk[N], st[N], ed[N];
char var[N];
void Get(int id, int to) {
int i, n = strlen(s[id] + 1); i = 2; st[to] = ed[to] = 0;
while (s[id][i] == ' ') i++; var[to] = s[id][i++];
while (s[id][i] == ' ') i++;
while (s[id][i] != ' ') {
if (s[id][i] == 'n') st[to] = INF;
else st[to] = st[to] * 10 + (s[id][i] - '0');
i++;
}
while (s[id][i] == ' ') i++;
while (s[id][i] != ' ' && s[id][i] != 0) {
if (s[id][i] == 'n') ed[to] = INF;
else ed[to] = ed[to] * 10 + (s[id][i] - '0');
i++;
}
}
void work() {
int i, j, CM = 0, nowCm = 0, stCM = 0;
L = read(); scanf("%s\n", com + 1); top = 0;
for (i = 1; i <= L; i++) gets(s[i] + 1);
for (i = 1; i <= L; i++) {
if (s[i][1] == 'F') {
stk[++top] = i; Get(i, top); nowCm = 0;
for (j = 1; j < top; j++) {
if (var[j] == var[top])
return (void) puts("ERR");
}
for (j = 1; j <= top; j++)
if (st[j] != INF && ed[j] == INF) nowCm++;
else if (st[j] == INF && ed[j] != INF) break;
else if (st[j] != INF && ed[j] != INF) {
if (st[j] > ed[j]) break;
}
CM = max(CM, nowCm);
}
else {
top--;
if (top < 0) return (void) puts("ERR");
}
}
if (top > 0) return (void) puts("ERR");
if (com[3] == '1') stCM = 0;
else {
int w = strlen(com + 1);
for (i = 5; i < w; i++) stCM = stCM * 10 + (com[i] - '0');
}
puts(CM == stCM ? "Yes" : "No");
}
int main() {
//freopen("complexity.in", "r", stdin);
//freopen("complexity.out", "w", stdout);
int T = read();
while (T--) work();
return 0;
}
T3 park
稍有难度的题来了……在考场上Tarjan写炸丢了30分[挫败]
先在反图上以
n
为起点跑最短路,记
先考虑有无数条合法路径的条件,容易想到,有无数条合法路径,当且仅当图存在零环并且存在一条长度不大于
dis[1]+K
的
1
到
1
到该节点的最短距离+该节点到
然后DP,看到
K
很小,就可以想到模型:
转移就是(
k
为与
f[i,j]=∑kf[k,dis[i]+j−val<i,k>−dis[k]]
。
刚开始发现这个方程有点儿问题(转移时出现环),但后来发现,
由于
val<i,k>+dis[k]
一定不小于
dis[i]
,所以
dis[i]+j−val<i,k>−dis[k]
一定不大于
j
,因此不存在零环的情况下,转移是不会出现环的。
由于
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5, M = 2e5 + 5, E = 53, INF = 0x3f3f3f3f;
int n, m, ecnt, K, nxt[M], adj[N], go[M], val[M], f[N][E], dis[N],
nxt2[M], adj2[N], go2[M], val2[M], ecnt2, que[M << 3], len, PYZ,
times, sum, bel[N], stk[N], num[N], top, dfn[N], low[N], disS[N];
bool vis[N], VIS[N], ins[N];
void add_edge(int u, int v, int w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
nxt2[++ecnt2] = adj2[v]; adj2[v] = ecnt2; go2[ecnt2] = u; val2[ecnt2] = w;
}
void Tarjan(int u) {
dfn[u] = low[u] = ++times; ins[stk[++top] = u] = 1;
for (int e = adj[u], v; e; e = nxt[e]) {
if (val[e]) continue;
if (!dfn[v = go[e]]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (ins[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
num[bel[u] = ++sum] = 1; ins[u] = 0; int v;
while (v = stk[top--], v != u) num[bel[v] = sum]++, ins[v] = 0;
}
}
void spfa(int S) {
int i; memset(dis, INF, sizeof(dis));
dis[que[len = 1] = S] = 0;
for (i = 1; i <= len; i++) {
int u = que[i]; vis[u] = 0;
for (int e = adj[u], v; e; e = nxt[e])
if (dis[u] + val[e] < dis[v = go[e]]) {
dis[v] = dis[u] + val[e];
if (!vis[v]) vis[que[++len] = v] = 1;
}
}
for (i = 1; i <= n; i++) disS[i] = dis[i];
}
void SPFA(int S) {
int i; memset(dis, INF, sizeof(dis));
dis[que[len = 1] = S] = 0;
for (i = 1; i <= len; i++) {
int u = que[i]; vis[u] = 0;
for (int e = adj2[u], v; e; e = nxt2[e])
if (dis[u] + val2[e] < dis[v = go2[e]]) {
dis[v] = dis[u] + val2[e];
if (!vis[v]) vis[que[++len] = v] = 1;
}
}
}
bool zeroCycle() {
times = sum = 0; int i; memset(num, 0, sizeof(num));
memset(dfn, 0, sizeof(dfn));
for (i = 1; i <= n; i++) if (!dfn[i]) Tarjan(i);
for (i = 1; i <= n; i++) if (num[bel[i]] > 1
&& disS[i] + dis[i] <= dis[1] + K) return 1;
return 0;
}
int DP(int u, int x) {
if (f[u][x] != -1) return f[u][x];
if (!x && u == n) return f[u][x] = 1; f[u][x] = 0;
for (int e = adj[u], v; e; e = nxt[e]) {
int d = dis[u] + x - val[e] - dis[v = go[e]];
if (d >= 0 && d <= K)
(f[u][x] += DP(v, d)) %= PYZ;
}
return f[u][x];
}
void work() {
memset(bel, 0, sizeof(bel));
memset(vis, 0, sizeof(vis));
memset(VIS, 0, sizeof(VIS));
ecnt = ecnt2 = 0; memset(adj, 0, sizeof(adj));
memset(adj2, 0, sizeof(adj2));
memset(f, -1, sizeof(f));
int i, x, y, z; n = read(); m = read(); K = read(); PYZ = read();
for (i = 1; i <= m; i++) {
x = read(); y = read(); z = read();
add_edge(x, y, z);
}
spfa(1); SPFA(n); int ans = 0; if (zeroCycle()) return (void) puts("-1");
for (i = 0; i <= K; i++) (ans += DP(1, i)) %= PYZ;
printf("%d\n", ans);
}
int main() {
//freopen("park.in", "r", stdin);
//freopen("park.out", "w", stdout);
int T = read();
while (T--) work();
return 0;
}