[NOI2018]网上同步赛游记

Day1

T1

一看这个东西有好多暴力分呀,打一下吧。然后就写了树和链的。和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;
}
T2

考虑到冒泡排序交换,仅仅是交换相邻的,于是就是逆序对个数。然并卵。
于是踏踏实实 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

T3

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 好像需要线段树合并,也是一脸懵。

Day2

T1

说实话挺水的,但是中国剩余定理不会…..真的好菜…..无奈之下只能写个 60pts 60 p t s 暴力了…道行太浅了。

T2

难题。防 AK A K 而出的一道题。 15pts 15 p t s 暴力,并不会写其他的…好菜啊 qaq q a q

T3

状压求哈密顿回路….暴力构图然后状压…理论 20pts 20 p t s

总结

还是学的太少了啊。不分析清楚就写代码的这个毛病要戒掉啊。
恭喜 pickupwin p i c k u p w i n 大佬的银牌!!!!真的太强了!!!

你可能感兴趣的:(OI与人生,比赛)