zoukankan      html  css  js  c++  java
  • GDOI2020 划水记

    因为 CSP 挂了 120 分,所以除了这里哪里都没能去...惨惨...

    今年虽然就在我们学校,但是我还是只能划水...不像 ntf 和 pb 如果 GDOI 死掉就直接进队了...

    Day -2

    首先打了一遍可持久化平衡树FHQTreap真的比Splay好写多了

    P6577 【模板】二分图最大权完美匹配

    大概就是给每个点分配一个标记 (A_i,B_j)。称满足 (A_i+B_jge dis(i,j)) 的为 可行顶标,由 (A_i+B_j=dis(i,j)) 的边构成的子图称为 相等子图。如果相等子图有完美匹配就做完了,所以关键就在于如何分配顶标,顺便用 KM 随便求一种匹配就完事了。

    对于一条增广路,计算出一个 (Delta),将左部点顶标减去 (Delta),右部点顶标加上 (Delta)。因为不会有一条边左点不在交错树上,右点在交错树上。于是 (Delta) 只要保证它仍然可行即可,取 (Delta=min(A_i+B_j-dis(i,j)))

    由于奇奇怪怪的原因,你需要写 BFS 版 KM。实现上面你还可以假装有一个虚点去匹配,再把虚点删掉就可以空出一个位置...

    这东西太神必了...抄完一遍代码之后仍然没怎么弄懂。

    int n, m, pre[M], mat[M], a, b;
    bool vis[M];
    LL ans, d[N][N], w[M], s[M], c;
    void bfs(int x){
    	memset(vis, 0, sizeof vis);
    	memset(pre, 0, sizeof pre);
    	memset(s, 0x3f, sizeof s);
    	int cur = 0, nxt = 0; mat[0] = x;
    	while(mat[cur]){
    		x = mat[cur]; vis[cur] = true; LL dis = 1e18;
    		for(Rint i = n + 1;i <= (n << 1);++ i) if(!vis[i]){
    			LL tmp = w[x] + w[i] - d[x][i - n];
    			if(chmin(s[i], tmp)) pre[i] = cur;
    			if(chmin(dis, s[i])) nxt = i;
    		}
    		w[mat[0]] -= dis; w[0] += dis;
    		for(Rint i = n + 1;i <= (n << 1);++ i)
    			if(vis[i]){w[mat[i]] -= dis; w[i] += dis;}
    			else s[i] -= dis;
    		cur = nxt;
    	}
    	while(cur){mat[cur] = mat[pre[cur]]; cur = pre[cur];}
    }
    int main(){
    	read(n); read(m);
    	memset(d, -0x3f, sizeof d);
    	for(Rint i = 1;i <= m;++ i){
    		read(a); read(b); read(c); chmax(d[a][b], c); chmax(w[a], d[a][b]);
    	}
    	for(Rint i = 1;i <= n;++ i) bfs(i);
    	for(Rint i = 1;i <= n;++ i) ans += d[mat[i + n]][i];
    	printf("%lld
    ", ans);
    	for(Rint i = n + 1;i <= (n << 1);++ i) printf("%d ", mat[i]);
    }
    

    扩展 BSGS

    对于 (a^xequiv b( ext{mod} p)),无解当且仅当 (gcd(a,p) ot|b)(b eq 1)

    (g=gcd(a,p)),则 (a^{x-1}cdotfrac{a}{g}equivfrac{b}{g}( ext{mod} frac{p}{g})),由于 (gcd(frac{a}{g},frac{p}{g})=1),所以 (a^{x-1}equivfrac{b}{g}(frac{a}{g})^{-1}( ext{mod} frac{p}{g})),递归到了一个 (p) 至少变为原来一半的子问题。直到 (gcd(a,p)=1) 时使用普通 BSGS 来做。

    注意在 (p) 不为质数的时候,你不能用 (a^{sqr*i-j}) 来计算而只能用 (a^{sqr*i+j}),因为...因为啥啊...

    LL gcd(LL a, LL b){return b ? gcd(b, a % b) : a;}
    void exgcd(LL a, LL b, LL &x, LL &y){
    	if(!b){x = 1; y = 0; return;}
    	exgcd(b, a % b, y, x); y -= a / b * x;
    }
    LL BSGS(LL a, LL b, LL p){
    	unordered_map<LL, int> S; a %= p;
    	LL sqr = ceil(sqrt(p)), now = 1, tmp = ksm(a, sqr, p), x, y;
    	exgcd(tmp, p, x, y); tmp = (x % p + p) % p;
    	for(Rint i = 0;i <= sqr;++ i, now = now * a % p) if(!S.count(now)) S[now] = i;
    	now = b;
    	for(Rint i = 0;i <= sqr;++ i, now = now * tmp % p) if(S.count(now)) return i * sqr + S[now];
    	return -1e9;
    }
    LL exBSGS(LL a, LL b, LL p){
    	LL g, x, y, sd = 1; int k = 0;
    	if(b == 1) return 0;
    	while((g = gcd(a, p)) > 1){
    		if(b % g) return -1; p /= g; ++ k; b /= g;
    		sd = a / g * sd % p; if(b == 1) return k;
    	}
    	exgcd(sd, p, x, y); b = (b * x % p + p) % p;
    	return BSGS(a, b, p) + k;
    }
    int main(){
    	LL a, p, b;
    	while(true){
    		read(a); read(p); read(b);
    		if(!a || !p || !b) return 0;
    		LL ans = exBSGS(a, b, p); a %= p;
    		if(ans < 0) puts("No Solution");
    		else printf("%lld
    ", ans);
    	}
    }
    

    无源汇上下界可行流

    对于每个点计算 (in_x)(out_x) 表示连向 (x) 和连出 (x) 的边的流量下界之和。然后把每条边容量设为上界-下界。设一个虚拟源点和虚拟汇点 (s,t),若 (in_x>out_x) 则连一条 ((s,x,in_x-out_x)),否则连一条 ((x,t,out_x-in_x)),若满流则原图存在可行流。

    (就是使用不需要流量平衡的源点和汇点来平衡下界的流量)

    有源汇上下界可行流

    连一条 ((t,s,+infty)),然后跑无源汇上下界可行流。

    有源汇上下界最大流

    先跑一遍有源汇上下界最大流,目前的流量是 (flow_1),然后看还能流多少。

    此时应该把 ((t,s,+infty)) 删掉,然后在原图源汇上跑一遍最大流,设流量为 (flow_2),则答案为 (flow_1+flow_2)

    #include<bits/stdc++.h>
    #define Rint register int
    #define MP make_pair
    #define PB push_back
    #define fi first
    #define se second
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pii;
    const int N = 1503, M = 1000000, mod = 998244353;
    inline int ksm(int a, int b){
    	int res = 1;
    	for(;b;b >>= 1, a = (LL) a * a % mod) if(b & 1) res = (LL) res * a % mod;
    	return res;
    }
    template<typename T>
    inline void read(T &x){
    	int ch = getchar(); x = 0; bool f = false;
    	for(;ch < '0' || ch > '9';ch = getchar()){f |= ch == '-'; if(ch == EOF) exit(0);}
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
    	if(f) x = -x;
    }
    template<typename T>
    inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    template<typename T>
    inline bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
    int n, m, S, T, deg[N], head[N], to[M], nxt[M], cap[M], cnt, ans, sum;
    void add(int a, int b, int c){
    	to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; cap[cnt] = c;
    	to[++ cnt] = a; nxt[cnt] = head[b]; head[b] = cnt; cap[cnt] = 0;
    }
    int dep[N], cur[N], q[N], f, r;
    bool bfs(){
    	memset(dep, -1, sizeof dep);
    	memcpy(cur, head, sizeof cur);
    	f = r = dep[S] = 0; q[r ++] = S;
    	while(f < r){
    		int u = q[f ++];
    		for(Rint i = head[u];i;i = nxt[i])
    			if(dep[to[i]] == -1 && cap[i]){
    				dep[to[i]] = dep[u] + 1;
    				q[r ++] = to[i];
    			}
    	}
    	return ~dep[T];
    }
    int dfs(int x, int lim){
    	if(!lim || x == T) return lim;
    	int flow = 0, f;
    	for(Rint i = cur[x];i;i = nxt[i]){
    		cur[x] = i;
    		if(dep[to[i]] == dep[x] + 1 && (f = dfs(to[i], min(lim, cap[i])))){
    			flow += f; lim -= f; cap[i] -= f; cap[i ^ 1] += f; if(!lim) break;
    		}
    	}
    	return flow;
    }
    int dinic(){int ans = 0; while(bfs()) ans += dfs(S, 1e9); return ans;}
    void solve(){
    	memset(head, 0, sizeof head); cnt = 1; sum = 0;
    	memset(deg, 0, sizeof deg);
    	read(n); read(m); S = n + m + 1; T = S + 1;
    	for(Rint i = 1, x;i <= m;++ i){read(x); add(n + i, T, 1e9 - x); deg[T] += x; deg[n + i] -= x;}
    	for(Rint i = 1, c, d, t, l, r;i <= n;++ i){
    		read(c); read(d); add(S, i, d);
    		while(c --){
    			read(t); read(l); read(r); ++ t;
    			add(i, n + t, r - l); deg[i] -= l; deg[n + t] += l;
    		}
    	} S += 2; T += 2;
    	for(Rint i = 1;i <= T - 2;++ i)
    		if(deg[i] > 0) add(S, i, deg[i]), sum += deg[i];
    		else if(deg[i] < 0) add(i, T, -deg[i]);
    	add(T - 2, S - 2, 1e9);
    	if(dinic() != sum){puts("-1"); return;}
    	ans = cap[cnt]; cap[cnt] = cap[cnt ^ 1] = 0; S -= 2; T -= 2;
    	printf("%d
    ", ans + dinic());
    }
    int main(){while(true){solve(); putchar('
    ');}}
    

    有源汇上下界最小流

    跟上一个类似,考虑能少流多少流量,就是从原图汇点向源点跑最大流,然后减去这个流量。

    ExKMP

    啥都别说了,learn by heart.

    now = p0 = 0;
    while(s[now] == t[now] && now < m) ++ now;
    ext[0] = now;
    for(Rint i = 1;i < n;++ i){
          if(i + nxt[i - p0] < p0 + ext[p0]) ext[i] = nxt[i - p0];
          else {
                now = max(ext[p0] + p0 - i, 0);
                while(t[now] == s[now + i] && now < m && now + i < n) ++ now;
                ext[i] = now; p0 = i;
          }
    }
    

    SA

    看同学在做这道题,我就也去尝试了一下...然后调了一个下午还是没有调出来...

    最后发现原来只是一个 sb 错误...我人药丸...

    #include<bits/stdc++.h>
    #define Rint register int
    #define PB push_back
    using namespace std;
    typedef long long LL;
    const int N = 222222, M = N * 22, K = M << 1;
    template<typename T>
    inline void read(T &x){
    	int ch = getchar(); x = 0; bool f = false;
    	for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
    	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
    	if(f) x = -x;
    }
    template<typename T>
    inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    int T, n, na, nb, m, la[N], ra[N], lb[N], rb[N], rak[N], tmp[N], *x = rak, *y = tmp, sa[N], c[N], ht[18][N], lg2[N];
    char s[N];
    struct Seg {
    	int lb, len, id;
    	inline Seg(int _a = 0, int _b = 0, int _c = 0): lb(_a), len(_b), id(_c){}
    	inline bool operator < (const Seg &o) const {
    		if(len != o.len) return len > o.len; return id < o.id;
    	}
    } seg[N<<1];
    void Qsort(){
    	memset(c + 1, 0, m << 2);
    	for(Rint i = 1;i <= n;++ i) ++ c[x[y[i]]];
    	for(Rint i = 1;i <= m;++ i) c[i] += c[i - 1];
    	for(Rint i = n;i;-- i) sa[c[x[y[i]]] --] = y[i];
    }
    void Ssort(){
    	m = 128;
    	for(Rint i = 1;i <= n;++ i){
    		x[i] = s[i]; y[i] = i;
    	}
    	Qsort();
    	for(Rint w = 1, p;w < n;w <<= 1, m = p, p = 0){
    		for(Rint i = n - w + 1;i <= n;++ i) y[++ p] = i;
    		for(Rint i = 1;i <= n;++ i) if(sa[i] > w) y[++ p] = sa[i] - w;
    		Qsort(); swap(x, y);
    		x[sa[1]] = p = 1;
    		for(Rint i = 2;i <= n;++ i) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + w] == y[sa[i - 1] + w]) ? p : ++ p;
    		if(p >= n) break;
    	}
    	for(Rint i = 1;i <= n;++ i) rak[sa[i]] = i;
    	for(Rint i = 1, k = 0;i <= n;++ i){
    		if(k) -- k;
    		if(rak[i] == 1) continue;
    		int j = sa[rak[i] - 1];
    		while(s[i + k] == s[j + k]) ++ k;
    		ht[0][rak[i]] = k;
    	}
    	for(Rint i = 1;i < 18;++ i) // sb 错误
    		for(Rint j = 1;j <= n - (1 << i) + 1;++ j)
    			ht[i][j] = min(ht[i - 1][j], ht[i - 1][j + (1 << i - 1)]);
    }
    int cnt, rcnt, rt[N], ls[M], rs[M], d[M], q[M], fr, re, head[M], to[K], nxt[K], ecnt;
    LL ans, dp[M];
    void add(int u, int v){to[++ ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt; ++ d[v];}
    void modify(int &x, int L, int R, int pos, int nod){
    	++ cnt; ls[cnt] = ls[x]; rs[cnt] = rs[x]; if(x) add(cnt, x); x = cnt;
    	if(L == R){add(x, nod); return;}
    	int mid = L + R >> 1;
    	if(pos <= mid){modify(ls[x], L, mid, pos, nod); add(x, ls[x]);}
    	else {modify(rs[x], mid + 1, R, pos, nod); add(x, rs[x]);}
    }
    void query(int x, int L, int R, int l, int r, int nod){
    	if(!x) return; if(l <= L && R <= r){add(nod, x); return;}
    	int mid = L + R >> 1;
    	if(l <= mid) query(ls[x], L, mid, l, r, nod);
    	if(mid < r) query(rs[x], mid + 1, R, l, r, nod);
    }
    void solve(){
    	scanf("%s", s + 1); n = strlen(s + 1); Ssort(); read(na);
    	for(Rint i = 1;i <= na;++ i){
    		read(la[i]); read(ra[i]);
    		seg[i] = Seg(rak[la[i]], ra[i] - la[i] + 1, i);
    	} read(nb);
    	for(Rint i = 1;i <= nb;++ i){
    		read(lb[i]); read(rb[i]);
    		seg[na + i] = Seg(rak[lb[i]], rb[i] - lb[i] + 1, na + i);
    	}
    	sort(seg + 1, seg + na + nb + 1); cnt = na + nb;
    	for(Rint i = 1;i <= na + nb;++ i){
    		Seg &p = seg[i];
    		if(p.id <= na){
    			++ rcnt; modify(rt[rcnt]=rt[rcnt-1], 1, n, p.lb, p.id);
    		} else {
    			int L = p.lb, R = p.lb;
    			for(Rint j = lg2[p.lb - 1];~j;-- j) if(L - (1 << j) >= 1 && ht[j][L - (1 << j) + 1] >= p.len) L -= 1 << j;
    			for(Rint j = lg2[n - p.lb];~j;-- j) if(R + (1 << j) <= n && ht[j][R + 1] >= p.len) R += 1 << j;
    			query(rt[rcnt], 1, n, L, R, p.id);
    		}
    	}
    	read(m); while(m --){int x, y; read(x); read(y); add(x, y + na);}
    	for(Rint i = 1;i <= cnt;++ i) if(!d[i]){q[re ++] = i; if(i <= na) dp[i] = ra[i] - la[i] + 1;}
    	while(fr < re){
    		int u = q[fr ++]; chmax(ans, dp[u]);
    		for(Rint i = head[u];i;i = nxt[i]){
    			int &v = to[i]; chmax(dp[v], dp[u]);
    			if(!-- d[v]){q[re ++] = v; if(v <= na) dp[v] += ra[v] - la[v] + 1;}
    		}
    	}
    	if(re == cnt) printf("%lld
    ", ans); else puts("-1");
    	for(Rint i = 1;i <= cnt;++ i) d[i] = dp[i] = ls[i] = rs[i] = head[i] = 0;
    	for(Rint i = 1;i <= rcnt;++ i) rt[i] = 0; fr = re = rcnt = ans = ecnt = 0;
    }
    int main(){
        read(T); lg2[0] = -1;
    	for(Rint i = 1;i < N;++ i) lg2[i] = lg2[i >> 1] + 1;
    	while(T --) solve();
    }
    

    Day -1

    早上打模拟赛被打自闭了...

    点分树

    普通的点分树用来维护一些路径相关的东西...通过在点分中心统计贡献来降低复杂度...

    点分树可以动态加点,像替罪羊树一样在某一个子树过大的时候暴力重构...紫荆花之恋比较自闭,就写了 [WC2018] 即时战略

    #include<bits/stdc++.h>
    #include"rts.h"
    #define Rint register int
    using namespace std;
    const int N = 300003;
    bool vis[N];
    int a[N];
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    void workLine(int n){
    	for(Rint i = 1;i < n;++ i) a[i] = i + 1;
    	shuffle(a + 1, a + n, rng); vis[1] = 1;
    	int l = 1, r = 1;
    	for(Rint i = 1;i < n;++ i) if(!vis[a[i]]){
    		int to = a[i], now, x = explore(l, to);
    		if(!vis[x]){vis[x] = true; now = x; l = to;}
    		else {now = r; r = to;}
    		while(!vis[to]) vis[now = explore(now, to)] = true;
    	}
    }
    int rt, siz[N], dsiz[N], ddep[N], dfa[N], wson[N], head[N], to[N << 1], nxt[N << 1];
    bool rch[N];
    void add(int a, int b){static int cnt = 0; to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;}
    template<typename T>
    inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    int find(int x, int f, int tot){
    	siz[x] = 1; wson[x] = 0; int cen = 0;
    	for(Rint i = head[x];i;i = nxt[i])
    		if(to[i] != f && !vis[to[i]]){
    			int tmp = find(to[i], x, tot);
    			chmax(wson[x], siz[to[i]]); siz[x] += siz[to[i]];
    			if(!cen || wson[tmp] < wson[cen]) cen = tmp;
    		}
    	chmax(wson[x], tot - siz[x]);
    	if(!cen || wson[x] < wson[cen]) cen = x; return cen;
    }
    void clear(int x, int f, int dep){
    	ddep[x] = dfa[x] = dsiz[x] = vis[x] = 0;
    	for(Rint i = head[x];i;i = nxt[i])
    		if(to[i] != f && ddep[to[i]] >= dep)
    			clear(to[i], x, dep);
    }
    void divide(int x){
    	vis[x] = true;
    	for(Rint i = head[x];i;i = nxt[i])
    		if(!vis[to[i]]){
    			int tmp = siz[x] < siz[to[i]] ? dsiz[x] - siz[x] : siz[to[i]], cen = find(to[i], 0, tmp);
    			dfa[cen] = x; ddep[cen] = ddep[x] + 1; dsiz[cen] = tmp; divide(cen);
    		}
    }
    void rebuild(int x){
    	int dep = ddep[x], tot = dsiz[x], fa = dfa[x];
    	clear(x, 0, dep); int cen = find(x, 0, tot);
    	ddep[cen] = dep; dsiz[cen] = tot; dfa[cen] = fa;
    	if(rt == x) rt = cen; divide(cen);
    }
    void reach(int to){
    	int now = rt;
    	while(!rch[to]){
    		int nxt = explore(now, to);
    		if(rch[nxt]){
    			while(dfa[nxt] != now) nxt = dfa[nxt];
    		} else {
    			rch[nxt] = vis[nxt] = true; dsiz[nxt] = 0; ddep[nxt] = ddep[now] + 1; dfa[nxt] = now;
    			for(Rint i = nxt;i;i = dfa[i]) ++ dsiz[i]; add(now, nxt); add(nxt, now);
    			int lst = 0;
    			for(Rint i = nxt;dfa[i];i = dfa[i]) if(dsiz[i] > 0.7 * dsiz[dfa[i]]) lst = dfa[i];
    			if(lst) rebuild(lst);
    		} now = nxt;
    	}
    }
    void play(int n, int T, int dataType){
    	if(dataType == 3){workLine(n); return;}
    	rch[rt = 1] = vis[1] = true;
    	for(Rint i = 1;i < n;++ i) a[i] = i + 1;
    	shuffle(a + 1, a + n, rng);
    	for(Rint i = 1;i < n;++ i) reach(a[i]);
    }
    

    Day 0

    没有模拟赛,本来准备开昨天 Global Round 8 的 VP,也咕咕咕了。

    一个上午光忙着换机房了...什么题都没做...

    下午搞了几局扫雷,晚上和其他大佬做了一些 CF 低等难度信心题。同年级不参加省选的人都去旅游了...我(e^2)...

    写了一遍 LCT 模板,虽然没有一次写对但是总归是 <30min 了,NTF 还蜜汁 TLE,我人傻了:(

    Day 1

    7:43 am

    晚上还是一如既往的没睡好,早上起来吃完饭来到信息楼,发现加了一些封条和栅栏就直接绕过去了

    来到401腐败,还是自闭,啥都不想写...看看之前做过的题吧...

    转发一个 SF 神仙做的省选地图

    GD 以前这么自闭的都联考了,ZJ 和 FJ 还要坚持出自己的毒瘤题Nice-a

    8:30 a.m.

    先写了个板子。

    8:36 a.m.

    看题目。

    T1 看上去比较复杂,先放着。

    T2 题目背景是小葱,极度熟悉你还可以在博客里面找到一道极其类似的题的题解

    9:02 a.m.

    过 T2 大样例。

    10:35 a.m.

    写完 T1 开始拍。

    因为我码力 tcl,所以本来想着要卡常就写了树状数组,后来写着写着烦的要死就直接上了个 map...

    11:07 a.m.

    拍上了(每次要么暴力写挂要么数据生成器写挂),测了速发现被卡常了...以为是少爷机就可以过去,但是出来才知道不开 O2,喜提 60 分

    0:35 p.m.

    T3 想自闭了,来写暴力。

    Day 2

    8:30 a.m.

    本来想着进考场先写个板子,然而写到一半被叫停了...

    开场看了个题,T1 好像是卡常的状压dp,T2,T3没什么思路

    9:57 a.m.

    写完了 T1,测了速跑了 3s,也不知道少爷机能不能跑过去。

    T2 只会分位然后根号分治,大概能搞 40 分。

    T3 直接各个部分分写就有 70 分了。

    0:12 p.m.

    该搞的差不多都搞完了,自闭了

    Day 4

    估分 (60+100+15+100+40+70=385),实际分数 (60+100+15+80+40+60=355),D2T1 被卡常了,D2T3 各个部分分写,可能就写挂了一点。

    总而言之还是十分丢人的,D2T2 和 D2T3 还是见过的 trick,但考场上面一自闭就想不出来了...考场上面大部分思路还是来源于第一印象,这就直接暴毙了。。。

    还是做题不够多,D2T2 ntf 见过两次了,我还看过一次题解,好像还没改...

    PB 拿了 B 类 rk1,NTF 压线进队不可能是评测挂了,ntf申诉失败,QWS 被学姐吊打了,我差亿点点就进去了,还是预料之中吧

  • 相关阅读:
    Java数据库操作学习
    c3p0配置
    CachedRowSet 接口
    Android Library的依赖方式及发布(转)
    网站测试
    MySQL Server逻辑架构
    Service生命周期
    Activity的生命周期
    Android应用框架中的四个核心要点
    Android 最新架构
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/13154101.html
Copyright © 2011-2022 走看看