NOIP模拟测试8
HZ怎么老考试啊23333
考试前一天占个坑。给自己的忠告:想不出正解就别想了,暴力打满Rank就不会难看QaQ
---华丽的分割线---
考完了,Rank14,我又boomboomboom了orz
最后T3的暴力还是没打出来,我就是个想不出正解还要ning想的DD
T1:匹配
我是Sb
一眼KMP,刚正不阿的cwy不会忘记了看猫片,果断\(O(N^2)\)暴力走人(
后来一看正解居然是蛤希,我草了,,,早知道就ning干力QAQ
考场上现推KMP估计还是能推出来的,如果能多想想就好了
简直对不起图巨
而且想不到KMP为啥不想想别的啊。。。懊悔中
复习下KMP:
\(nxt[i]\)表示了\(S[,i]\)的前缀最长border的位置,当我们要匹配一个新的字母,我们设定一个指针p = nxt[i - 1],如果S[i] = S[p+1]说明匹配大成功,p+1就是\(S[,i]\)的前缀最长border的位置,否则p指针一直往回跳,最恶情况就是无法匹配,一直跳到了1。
#include <bits/stdc++.h>
const int N = 300000 + 233;
int T, la, lb, nxt[N];
char a[N], b[N], add[5];
signed main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &la, &lb);
scanf("%s%s", a + 1, add);
a[la + 1] = '$', ++la;
for (int i = 1; i <= lb; i++) a[i + la] = a[i];
a[la + lb + 1] = add[0];
for (int i = 2; a[i]; i++) {
int p = nxt[i - 1];
while (p && a[i] != a[p + 1]) p = nxt[p];
if (a[i] == a[p + 1]) nxt[i] = p + 1;
}
printf("%d\n", nxt[la + lb + 1]);
memset(nxt, 0, sizeof(nxt));
}
return 0;
}
T2:回家
我离AC只差一个90w的数组
一眼求割点,速码开T3。T3写完,二眼好像不对,割点不一定在1-n路径上。于是赶回来修锅,建个圆方树,dfs求出1-n经过的圆点。
然后就MLE了????红太阳GMK说他数组开小了,我跟风给常数乘个10.
然后我就A了???
这题还是挺显然的,思路秒出
考试时候千万别吝啬空间,够开就开,QAQ
#include <bits/stdc++.h>
const int N = 2000000 + 233;
int T, n, m, ans;
struct Edge {int to, nxt;} e[N << 2], c[N << 2];
int ecnt, head[N], ccnt, hc[N], tot;
bool yes[N];
inline int R() {
int a = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a;
}
int low[N], dfn[N], num, stk[N], p;
inline void AddEdge(int f, int to) {
e[++ecnt] = {to, head[f]}, head[f] = ecnt;
}
inline void AddC(int f, int to) {
c[++ccnt] = {to, hc[f]}, hc[f] = ccnt;
}
void Tarjan(int x) {
dfn[x] = low[x] = ++num;
stk[++p] = x;
for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) {
if (!dfn[y]) {
Tarjan(y);
low[x] = std::min(low[x], low[y]);
if (dfn[x] == low[y]) {
AddC(x, ++tot), AddC(tot, x); int z;
do {
z = stk[p--], AddC(z, tot), AddC(tot, z);
} while (y != z);
}
} else low[x] = std::min(low[x], dfn[y]);
}
}
void dfs(int x, int fa) {
for (int i = hc[x], y = c[i].to; i; i = c[i].nxt, y = c[i].to) {
if (y != fa) {
dfs(y, x);
if (y == n) return (void) (yes[x] = 1);
else if (yes[y]) yes[x] = 1;
}
}
}
signed main() {
T = R();
while (T--) {
n = R(), m = R(), tot = n;
for (int i = 1, x, y; i <= m; i++)
x = R(), y = R(), AddEdge(x, y), AddEdge(y, x);
Tarjan(1);
dfs(1, 0);
for (int i = 2; i < n; i++)
if (yes[i]) ans++;
printf("%d\n", ans);
for (int i = 2; i < n; i++)
if (yes[i]) printf("%d ", i);
if (ans) printf("\n");
memset(head, 0, sizeof(head));
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(hc, 0, sizeof(hc));
memset(stk, 0, sizeof(stk));
memset(yes, 0, sizeof(yes));
num = ecnt = ccnt = ans = p = 0;
}
return 0;
}
T3:寿司
开始想着会不会是一个类似与Data Backup的贪心思路,推了一段时间开码,码完发现不对,完全失败,这时发现T2有问题去修锅。
修完锅继续想,zzz,想不出来,好像只会打暴力DFS,码码码,没码完到点了,GG
考完看题解,发现我过于Noob,无法看出出题人的显然性质。
我们看到环很自然就破环为链,这时我们枚举从上头选个环的断点。
$ \Theta \omega \Theta $