zoukankan      html  css  js  c++  java
  • 2018冬令营模拟测试赛(六)

    2018冬令营模拟测试赛(六)

    [Problem A]string

    试题描述

    TAT

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    题解

    一口一个前缀,二话不说建立 trie 树。

    为了避免算重,我们在统计一个串的时候要求在最后的分割位置统计它,即不存在更靠后的分割位置。为了达到这一点我们先枚举后半部分,由于后半部分是某个串的一个前缀,即 trie 树上从根到某个点 (u) 的一条路径,那么现在就是要求前面填的串满足一个性质。

    (v = fail[u]),即失配边指向的位置,(w) 是根节点到 (u) 的路径中刨去根节点到 (v) 的路径这个后缀的串所对应的节点(也即 (u) 在 trie 树上的 (k) 级祖先,(k) 为根到 (v) 的路径长度)。容易发现只要前面填的串不是 (v)失配树中的子树中的节点就好了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1000010
    #define maxa 30
    #define maxlog 20
    #define LL long long
    
    char str[maxn];
    int ToT, ch[maxn][maxa], dep[maxn], pa[maxn][maxlog];
    
    void Insert(char *s) {
    	int n = strlen(s), u = 1;
    	rep(i, 0, n - 1) {
    		int x = s[i] - 'a';
    		if(!ch[u][x]) ch[u][x] = ++ToT;
    		u = ch[u][x];
    	}
    	return ;
    }
    void build(int u) {
    	rep(i, 1, maxlog - 1) pa[u][i] = pa[pa[u][i-1]][i-1];
    	rep(c, 0, maxa - 1) if(ch[u][c]) {
    		pa[ch[u][c]][0] = u;
    		dep[ch[u][c]] = dep[u] + 1;
    		build(ch[u][c]);
    	}
    	return ;
    }
    int KthPar(int u, int k) {
    	rep(i, 0, maxlog - 1) if(k >> i & 1) u = pa[u][i];
    	return u;
    }
    int fa[maxn], tofa[maxn], siz[maxn], Q[maxn], hd, tl;
    void getfail() {
    	hd = tl = 0; Q[++tl] = 1;
    	while(hd < tl) {
    		int u = Q[++hd];
    		rep(c, 0, maxa - 1) if(ch[u][c]) {
    			int v = ch[u][c], j = fa[u];
    			while(j && !ch[j][c]) j = fa[j];
    			fa[v] = ch[j][c] ? ch[j][c] : 1;
    			if(fa[v] > 1) tofa[v] = KthPar(v, dep[fa[v]]);
    			Q[++tl] = v;
    		}
    	}
    	dwn(i, tl, 1) {
    		int u = Q[i];
    		siz[u]++; siz[fa[u]] += siz[u];
    	}
    	return ;
    }
    
    int main() {
    	read();
    	int n = read();
    	ToT = 1;
    	rep(i, 1, n) scanf("%s", str), Insert(str);
    	build(1);
    	getfail();
    	
    	LL ans = 0; siz[0] = 0;
    	rep(i, 2, ToT) ans += ToT - siz[tofa[i]] - !tofa[i]; // (ToT - 1) - (siz[tofa[i]] - 1)
    	printf("%lld
    ", ans);
    	
    	return 0;
    }
    

    [Problem B]tree

    试题描述

    QAQ

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    题解

    这是一道可以转化为基于深度维护信息的题,所以做法是长链剖分。

    (f(i, j)) 表示节点 (i) 的子树中,还需要向子树 (i) 外部延伸 (j) 的距离能够组成的三元组的点对的贡献(这只是一个状态,具体计算还需要维护 (sum a_0 + a_1)(sum a_0a_1))。

    在合并的时候我们可以暴力扫描一下其他子树的短链,然后把子树之间的贡献利用 (f(i, j)) 计算,同时合并更新 (f(i, j))。在重链上上移的时候,需要数组整体移位,这个东西记录一个移了多少位的变量就行了;在每一步移道位置 (0)(即 (j = 0) 那一位)时 (f(i, j)) 和当前节点也可以组成三元组,记得累计一下贡献。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    #define MOD 998244353
    #define LL long long
    
    int n, m, head[maxn], nxt[maxm], to[maxm], val[maxn];
    
    void AddEdge(int a, int b) {
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	swap(a, b);
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	return ;
    }
    
    #define pll pair <LL, LL>
    #define x first
    #define y second
    #define mp(x, y) make_pair(x, y)
    vector <pll> info[maxn]; // x: _sum{a0+a1}, y: _sum{a0*a1}
    int mxd[maxn], son[maxn], dep[maxn], clo, dfn[maxn], uid[maxn], top[maxn];
    void build(int u, int fa) {
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) {
    		dep[to[e]] = dep[u] + 1;
    		build(to[e], u);
    		if(!son[u] || mxd[son[u]] < mxd[to[e]]) son[u] = to[e];
    	}
    	mxd[u] = max(mxd[son[u]], dep[u]);
    	return ;
    }
    void gett(int u, int tp, int fa) {
    	if(u == tp) info[u].resize(mxd[u] - dep[u] + 3 << 1);
    	uid[dfn[u] = ++clo] = u; top[u] = tp;
    	if(son[u]) gett(son[u], tp, u);
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa && to[e] != son[u]) gett(to[e], to[e], u);
    	return ;
    }
    
    LL ans, sumv[maxn], cntv[maxn];
    void solve(int u, int fa) {
    	if(son[u]) solve(son[u], u);
    	int minus = mxd[u] - dep[u];
    	// printf("solve(%d)
    ", u);
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa && to[e] != son[u]) {
    		solve(to[e], u);
    		// printf("merge %d and %d
    ", u, to[e]);
    		rep(h, 0, mxd[to[e]] - dep[to[e]]) {
    			// printf("for height %d
    ", h);
    			int i = h + 1 + minus, j = dfn[to[e]] + h;
    			ans += info[top[u]][i].x * sumv[j] % MOD;
    			ans += info[top[u]][i].y * cntv[j] % MOD;
    			// printf("%d and %d: %lld * %lld + %lld * %lld = %lld
    ", u, to[e], info[top[u]][i].x, sumv[j], info[top[u]][i].y, cntv[j], info[top[u]][i].x * sumv[j] + info[top[u]][i].y * cntv[j]);;
    			i = dfn[u] + h; j = h + 1 + mxd[to[e]] - dep[to[e]];
    			ans += sumv[i] * info[to[e]][j].x % MOD;
    			ans += cntv[i] * info[to[e]][j].y % MOD;
    			// printf("also: %lld * %lld + %lld * %lld = %lld
    ", sumv[i], info[to[e]][j].x, cntv[i], info[to[e]][j].y, sumv[i] * info[to[e]][j].x + cntv[i] * info[to[e]][j].y);
    			ans %= MOD;
    		}
    		(info[top[u]][minus].x += info[to[e]][mxd[to[e]]-dep[to[e]]+1].x) %= MOD;
    		(info[top[u]][minus].y += info[to[e]][mxd[to[e]]-dep[to[e]]+1].y) %= MOD;
    		rep(h, 1, mxd[to[e]] - dep[to[e]] + 1) {
    			int i = h + minus, j = h + 1 + mxd[to[e]] - dep[to[e]], di = dfn[u] + h, dj = dfn[to[e]] + h - 1;
    			info[top[u]][i].x += sumv[di] * cntv[dj] % MOD + sumv[dj] * cntv[di] % MOD;
    			info[top[u]][i].y += sumv[di] * sumv[dj] % MOD;
    			(info[top[u]][i].x += info[to[e]][j].x) %= MOD;
    			// printf("+= %lld
    ", info[to[e]][j].x);
    			(info[top[u]][i].y += info[to[e]][j].y) %= MOD;
    			(sumv[di] += sumv[dj]) %= MOD; (cntv[di] += cntv[dj]) %= MOD;
    			// printf("for height %d
    merging: (a0+a1)%lld (a0*a1)%lld (sumv)%lld (cntv)%lld
    ", h, info[top[u]][i].x, info[top[u]][i].y, sumv[di], cntv[di]);
    		}
    	}
    	sumv[dfn[u]] = val[u]; cntv[dfn[u]] = 1;
    	(ans += info[top[u]][minus].x * val[u] % MOD + info[top[u]][minus].y) %= MOD;
    	// printf("ans += %lld * %lld + %lld = %lld
    ", info[top[u]][minus].x, val[u], info[top[u]][minus].y, info[top[u]][minus].x * val[u] + info[top[u]][minus].y);
    	return ;
    }
    
    int main() {
    	read();
    	n = read();
    	rep(i, 1, n - 1) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	rep(i, 1, n) val[i] = read();
    	
    	build(1, 0);
    	gett(1, 1, 0);
    	/*rep(u, 1, n) {
    		printf("[%d] top, son: %d, %d
    ", u, top[u], son[u]);
    		if(top[u] == u) printf("vector_size: %d
    ", info[u].size());
    	} // */
    	
    	solve(1, 0);
    	
    	printf("%lld
    ", ans);
    	
    	return 0;
    }
    

    [Problem C]heike

    试题描述

    QwQ

    ToT

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    注意:本题给出的数据范围是假的,应为 (n,m le 10^6)

    题解

    这题先要证明一下(略过)是个拟阵,但是我觉得考虑替换也可以意识到它是个贪心了。

    然后就是要上霍尔定理,这样我们可以得到:一个区间是满的当且仅当它所包含的 boys 总数等于区间长度。

    每加入一个 boy 的时候维护一下那些区间满了,每个区间包含它的满区间最短的是谁(由于“满”有可交、可并性,证明略,故这个是可以求的),这个可以在每次加入成功时 dp 一下。

    顺便维护一下一个区间中包含的最小权值的 boy,用于“假插入”询问。

    对于没加入的 boy,在包含它的最短满区间上打个标记,表示它是备选的,到时候如果某个 boy 被删了导致那个区间不满,就可以把这个 boy 加进去。

    最后把上面说的那个标记再 dp 下传一下,这样删掉一个 boy 就可以 (O(1)) 求出替补是谁。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 310
    #define maxm 1000010
    #define oo 2147483647
    #define LL long long
    #define pii pair <int, int>
    #define x first
    #define y second
    #define mp(x, y) make_pair(x, y)
    
    struct Boy {
    	int l, r, v, id;
    	Boy() {}
    	Boy(int _1, int _2, int _3, int _4): l(_1), r(_2), v(_3), id(_4) {}
    	bool operator < (const Boy& t) const { return v > t.v; }
    } bs[maxm];
    bool used[maxm];
    int n, real[maxm], cb, q, tot[maxn][maxn], inMin[maxn][maxn], getMax[maxn][maxn];
    pii Full[maxn][maxn];
    
    void upd(pii& a, pii b) {
    	if(!b.x) return ;
    	if(!a.x || a.y - a.x + 1 > b.y - b.x + 1) a = b;
    	return ;
    }
    
    int main() {
    	read();
    	n = read(); cb = read(); q = read();
    	rep(i, 1, cb) {
    		int l = read(), r = read(), v = read();
    		bs[i] = Boy(l, r, v, i);
    	}
    	
    	rep(i, 1, n) rep(j, i, n) inMin[i][j] = oo;
    	LL ans = 0;
    	sort(bs + 1, bs + cb + 1);
    	rep(i, 1, cb) real[bs[i].id] = i;
    	rep(i, 1, cb) {
    		Boy& b = bs[i];
    		if(!Full[b.l][b.r].x) {
    			used[i] = 1;
    			ans += b.v;
    			rep(l, 1, b.l) rep(r, b.r, n) tot[l][r]++, inMin[l][r] = min(inMin[l][r], b.v);
    			dwn(len, n, 1) rep(l, 1, n - len + 1) {
    				int r = l + len - 1;
    				if(tot[l][r] == r - l + 1) upd(Full[l][r], pii(l, r));
    				if(len > 1) upd(Full[l][r-1], Full[l][r]), upd(Full[l+1][r], Full[l][r]);
    			}
    		}
    		else {
    			pii& fu = Full[b.l][b.r];
    			getMax[fu.x][fu.y] = max(getMax[fu.x][fu.y], b.v);
    		}
    	}
    	dwn(len, n, 2) rep(l, 1, n - len + 1) {
    		int r = l + len - 1, now = getMax[l][r];
    		getMax[l][r-1] = max(getMax[l][r-1], now);
    		getMax[l+1][r] = max(getMax[l+1][r], now);
    	}
    	
    	printf("%lld
    ", ans);
    	while(q--) {
    		int tp = read();
    		if(tp == 1) {
    			int nl = read(), nr = read(), nv = read();
    			pii& fu = Full[nl][nr];
    			printf("%lld
    ", ans - inMin[fu.x][fu.y] + max(inMin[fu.x][fu.y], nv));
    		}
    		if(tp == 2) {
    			int i = real[read()];
    			if(!used[i]){ printf("%lld
    ", ans); continue; }
    			printf("%lld
    ", ans - bs[i].v + getMax[bs[i].l][bs[i].r]);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    mysql5.7 ERROR 1045 (28000): Access denied for user解决方法
    C++ json解决方案
    Gitblit无法查看单个文件解决方案
    git 拉取指定的远程分支(三种方式)
    全栈12
    git commit之后,想撤销commit
    video
    iframe
    git恢复之前版本的两种方法reset、revert
    Eclipse
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8177736.html
Copyright © 2011-2022 走看看