一看这个东西有好多暴力分呀,打一下吧。然后就写了树和链的。和zg大佬聊了一下,他说他只写了离线的,然后我就一直在想这个离线的做法,就连通块呗。但是跟暴力分也差不多,就算了吧。
然后最终只有 50pts 50 p t s 。
原因是: spfa s p f a 这个东西,它已经死了。(原话是:你为什么要写一个平方级的算法呢?)
正解是 kruskal k r u s k a l 重构树,也算是个裸题了。不过lzz大佬在知乎说可持久化并查集并不是只能用 O(Nlog²N) O ( N l o g ² N ) 去做(有待学习)。
#include
#include
#include
#include
using namespace std;
#define N 200010
#define M 400010
inline char gc() {
static char now[1<<16], *S, *T;
if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
return *S++;
}
inline int read() {
int x = 0; char c = gc();
while(c < '0' || c > '9') c = gc();
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
return x;
}
int T, n, m;
struct TEMP {
int u, v, l, a;
}temp[M];
inline bool operator < (const TEMP &A, const TEMP &B) {
return A.a > B.a;
}
struct edge {
int fr, to, l, a, next;
}e[M<<1]; int head[N], cnt;
inline void ins(int u, int v, int l, int a) {
e[++cnt] = (edge){u, v, l, a, head[u]};
head[u] = cnt;
}
int dis[N]; bool vis[N];
struct node {
int u, dis;
};
inline bool operator < (const node &A, const node &B) {
return A.dis > B.dis;
}
inline void dijkstra() {
for(int i = 1; i <= n; ++i) dis[i] = 0x7fffffff, vis[i] = 0;
dis[1] = 0;
priority_queue que;
que.push((node){1, 0});
while(!que.empty()) {
int u = que.top().u;
que.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(!vis[v] && dis[v] > dis[u] + e[i].l) {
dis[v] = dis[u] + e[i].l;
que.push((node){v, dis[v]});
}
}
}
}
int Fa[N<<1], tot, val[N<<1], son[N<<1][2];
int getFa(int x) {
if(x == Fa[x]) return x;
return (Fa[x] = getFa(Fa[x]));
}
int f[N<<1][19], g[N<<1][19], mn[N<<1], dep[N<<1];
void dfs(int x) {
for(int i = 0; i <= 1; ++i) {
int y = son[x][i];
if(y == f[x][0] || !y) continue;
dep[y] = dep[x] + 1;
dfs(y);
}
}
inline void kruskal() {
tot = n;
for(int i = 1; i <= (n<<1); ++i) Fa[i] = i, son[i][0] = son[i][1] = 0;
memset(f, 0, sizeof(f));
memset(g, 0x3f, sizeof(g));
memcpy(mn, dis, sizeof(mn));
memset(val, 0x3f, sizeof(val));
for(int i = 2; i <= cnt; ++i) {
int u = e[i].fr, v = e[i].to;
int fu = getFa(u), fv = getFa(v);
if(fu == fv) continue;
++tot; val[tot] = e[i].a;
mn[tot] = min(mn[fu], mn[fv]);
Fa[fu] = tot;
Fa[fv] = tot;
son[tot][0] = fu; son[tot][1] = fv;
f[fu][0] = tot;
f[fv][0] = tot;
}
dep[0] = 0; dep[tot] = 1;
dfs(tot);
for(int i = 1; i <= tot; ++i) g[i][0] = val[i];
}
inline void init_db() {
for(int j = 1; j <= 18; ++j)
for(int i = 1; i <= tot; ++i) {
f[i][j] = f[f[i][j - 1]][j - 1];
g[i][j] = min(g[i][j - 1], g[f[i][j - 1]][j - 1]);
}
}
int Q, K, S, lastans;
inline int ask_db(int v, int p) {
int V = v;
for(int i = 18; i >= 0; --i) {
if(f[v][i] && g[v][i] > p) {
v = f[v][i];
}
}
if(g[v][0] > p) return v;
for(int j = 18; j >= 0; --j) {
if(dep[f[V][j]] > dep[v]) {
V = f[V][j];
}
}
return V;
}
int main() {
T = read();
while(T--) {
memset(head, 0, sizeof(head));
cnt = 1;
n = read(); m = read();
for(int i = 1; i <= m; ++i) {
int u = read(), v = read(), l = read(), a = read();
temp[i] = (TEMP){u, v, l, a};
}
sort(temp+1, temp+m+1);
for(int i = 1; i <= m; ++i) {
ins(temp[i].u, temp[i].v, temp[i].l, temp[i].a);
ins(temp[i].v, temp[i].u, temp[i].l, temp[i].a);
}
dijkstra();
kruskal();
init_db();
lastans = 0;
Q = read(); K = read(); S = read();
for(int i = 1; i <= Q; ++i) {
int v = read(), p = read();
v = (v + K * lastans % n - 1) % n + 1;
p = (p + K * lastans % (S + 1)) % (S + 1);
int x = ask_db(v, p);
printf("%d\n", (lastans = mn[x]));
}
}
return 0;
}
考虑到冒泡排序交换,仅仅是交换相邻的,于是就是逆序对个数。然并卵。
于是踏踏实实 8pts 8 p t s 暴力。
听说正解是要先写出 dp d p ,然后打个表发现是 Catalan C a t a l a n Number N u m b e r 。
总之我并不会 qaq q a q 。
SAM S A M 。 68pts 68 p t s 卡在了怎么求每一个位置时产生的不同子串的个数。自己在自己上跑也不对(事实证明就是这样的,打标记跳 fail f a i l 统计)。
#include
#include
#define N 500010
#define M 1000010
inline int read() {
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();}
return x;
}
int n, Q, m;
char s[N], str[M];
int ch[N<<1][26], fa[N<<1], mx[N<<1], last = 1, cnt = 1;
inline void extend(int c) {
int np = ++cnt; mx[np] = mx[last] + 1;
int p = last; last = np;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) fa[np] = 1;
else {
int q = ch[p][c];
if(mx[q] == mx[p] + 1) fa[np] = q;
else {
int nq = ++cnt; mx[nq] = mx[p] + 1;
fa[nq] = fa[q]; memcpy(ch[nq], ch[q], sizeof(ch[nq]));
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
fa[np] = fa[q] = nq;
}
}
}
int MaxLen[M], newsub[M];
struct SAM {
int ch[M<<1][26], fa[M<<1], mx[M<<1], last, cnt, val[M<<1];
bool vis[M<<1];
SAM() {
cnt = last = 1;
}
inline void init() {
for(int i = 1; i <= cnt; ++i) {
memset(ch[i], 0, sizeof(ch[i]));
mx[i] = fa[i] = 0;
val[i] = 0;
vis[i] = 0;
}
last = cnt = 1;
}
inline void extend(int c) {
int np = ++cnt; mx[np] = mx[last] + 1; val[np] = 1;
int p = last; last = np;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) fa[np] = 1;
else {
int q = ch[p][c];
if(mx[q] == mx[p] + 1) fa[np] = q;
else {
int nq = ++cnt; mx[nq] = mx[p] + 1;
fa[nq] = fa[q]; memcpy(ch[nq], ch[q], sizeof(ch[nq]));
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
fa[np] = fa[q] = nq;
}
}
}
inline void work() {
int now = 1;
for(int i = 1; i <= m; ++i) {
int c = str[i] - 'a';
int tot = 0;
now = ch[now][c];
tot = mx[now] - mx[fa[now]];
vis[now] = 1;
int u = now;
while(fa[fa[u]]) {
u = fa[u];
if(vis[u]) break;
vis[u] = 1;
tot+= mx[u] - mx[fa[u]];
}
newsub[i] = tot;
}
}
}sam;
int main() {
scanf("%s", s+1); n = strlen(s+1);
for(int i = 1; i <= n; ++i) extend(s[i] - 'a');
Q = read();
while(Q--) {
scanf("%s", str+1);
int l = read(), r = read();
m = strlen(str+1);
int now = 1, len = 0;
for(int i = 1; i <= m; ++i) {
int c = str[i] - 'a';
if(ch[now][c]) now = ch[now][c], ++len;
else {
while(now && !ch[now][c]) now = fa[now];
if(!now) now = 1, len = 0;
else len = mx[now] + 1, now = ch[now][c];
}
MaxLen[i] = len;
}
sam.init();
for(int i = 1; i <= m; ++i) {
sam.extend(str[i] - 'a');
}
sam.work();
long long ans = 0;
for(int i = 1; i <= m; ++i) {
int l1 = 1, r1 = newsub[i];
int l2 = i - MaxLen[i] + 1, r2 = i;
if(l2 > r1 || r2 < l2 || r1 < l1) continue;
ans+= r1 - l2 + 1;
}
long long tot = 0;
for(int i = 1; i <= m; ++i) tot+= newsub[i];
printf("%lld\n", tot - ans);
}
return 0;
}
100pts 100 p t s 好像需要线段树合并,也是一脸懵。
说实话挺水的,但是中国剩余定理不会…..真的好菜…..无奈之下只能写个 60pts 60 p t s 暴力了…道行太浅了。
难题。防 AK A K 而出的一道题。 15pts 15 p t s 暴力,并不会写其他的…好菜啊 qaq q a q
状压求哈密顿回路….暴力构图然后状压…理论 20pts 20 p t s 。
还是学的太少了啊。不分析清楚就写代码的这个毛病要戒掉啊。
恭喜 pickupwin p i c k u p w i n 大佬的银牌!!!!真的太强了!!!