首页 > 其他分享 >Manthan, Codefest 18 (rated, Div. 1 + Div. 2) (E,F,G)

Manthan, Codefest 18 (rated, Div. 1 + Div. 2) (E,F,G)

时间:2022-11-03 16:03:47浏览次数:75  
标签:... Manthan int Codefest 30 seg Div SG dp

Link

E

m次操作,每次加边后询问最大旅行团。
旅行团的定义:旅行团中的每个人都至少有k个邻接点在团里。

显然会肯定很想全选,但是有的人压根没有k个邻接点,只能直接删掉,然后一直狂暴删点,删到最后就知道最大旅行团多大了。 但是这是 $O(n^2)$ 那么考虑倒着做,每次删边即可。

F

function z(array a, integer k):
    if length(a) < k:
        return 0
    else:
        b = empty array
        ans = 0
        for i = 0 .. (length(a) - k):
            temp = a[i]
            for j = i .. (i + k - 1):
                temp = max(temp, a[j])
            append temp to the end of b
            ans = ans + temp
        return ans + z(b, k)

给出 \(a,k\),求 \(z(a,k)\)

以下用 $[l,r]$ 表示 ${max}_{i=l}^r a_i$

考虑k=3的情况。

数组变化如下

\[[1,3],[2,4],[3,5]...\\ [1,5],[2,6],[3,7]...\\ [1,7]...\\ ...\\ [1,gap+1]...[n-gap,n] \]

也就是说 \(gap=r-l\) 的值是 \((k-1),2(k-1),...\)

枚举gap来计算是困难的,考虑 \(a_i\) 的贡献,\(a_i\) 向左连续不大于他的最左的是 \(a_l\),向右连续小于他的最右的是 \(a_r\)(为了防止相同的 \(a_i\) 干扰计算)

设 \(calc(l,r)\) 为区间 \(l,r\) 中会出现的区间个数,那么 \(a_i\) 贡献次数为 \(calc_{l,r}-calc_{l,i-1}-calc_{i+1,r}\),这个容易计算

G

vp写完F还有5min,然后pbb吹水去了。。看了半天题解。。

A和B玩游戏,二人轮流操作,A先手。

初始有一个字符串 \(s\),每次操作玩家可以选一个喜欢的字符 \(c\),把字符串 \(c\) 删掉,这样字符串就断开成多个,也就变成多个子游戏。不能操作者输。
xq93Ax.png

设字符 \(c\) 在字符串中出现位置为 \(a_1,a_2,...,a_k\)

会把一个字符串分割成上图那样。(绿色、红色部分内部没有字符 \(c\))

首先,子游戏SG值异或和是当前游戏的SG值(所以对于下图那个字符串的进行操作 \(c\) 后该状态的SG值就是绿色部分的异或和)

如果每次遇到询问都暴力求解SG函数值显然太慢了,我们发现有大量的重复计算部分。

那么可以dp预处理绿色部分(指对于每个 \(c\),每个绿色部分单独当成一个询问那样预处理),红色部分的数量是 \(O(26n)\) 级别的,可以记忆化。

对于每个字符 \(c\),对绿色部分做前缀和。然后就可以在 \(O(26n)\) 的复杂度内计算的所有询问的SG函数值。

具体实现可以看下代码,各数组的定义应该很容易得出(

那个SG值求mex的地方看着比较怪,官方题解是这么写的(暴露了我的补题写的和官方std差不多的事实),原因是你顶多 26​ 个后继,mex 取值肯定在 \([0,26]\) 内。

const int N = 1e5 + 10, alf = 26;
char s[N]; int n, tmp[30], lst[30][N], nxt[30][N], dplst[30][N], dpnxt[30][N], dp[30][N], rk[N];
vector<int>vec[30];
vector<PII>seg;
bool cmp(PII x, PII y) { return x.se - x.fi < y.se - y.fi; }
int dp_slow(int l, int r) {
	int mask = 0;
	for(int c = 0; c < alf; c++) {
		int L = nxt[c][l], R = lst[c][r];
		if(L > r) continue;
		int ret = 0;
		for(int i = rk[L] + 1; i <= rk[R]; i++) ret ^= dp[c][i];
		if(l < L) {
			if(dpnxt[c][l] == -1) dpnxt[c][l] = dp_slow(l, L - 1);
			ret ^= dpnxt[c][l];
		}
		if(R < r) {
			if(dplst[c][r] == -1) dplst[c][r] = dp_slow(R + 1, r);
			ret ^= dplst[c][r];
		}
		if(ret < alf) mask |= (1 << ret);
	}
	for(int i = 0; i < alf; i++)
		if(!(mask & (1 << i))) return i;
	return alf;
}
int dp_fast(int l, int r) {
	int mask = 0;
	for(int c = 0; c < alf; c++) {
		int L = nxt[c][l], R = lst[c][r];
		if(L > r) continue;
		//cout<<"dp_fastw: "<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
		int ret = (dp[c][rk[R]] ^ dp[c][rk[L]]);
		if(l < L) {
			if(dpnxt[c][l] == -1) dpnxt[c][l] = dp_fast(l, L - 1);
			ret ^= dpnxt[c][l];
		}
		if(R < r) {
			if(dplst[c][r] == -1) dplst[c][r] = dp_fast(R + 1, r);
			ret ^= dplst[c][r];
		}
		if(ret < alf) mask |= (1 << ret);
	}
	for(int i = 0; i < alf; i++)
		if(!(mask & (1 << i))) return i;
	return alf;
}
void init() {
	for(int i = 1; i <= n; i++) {
		int c = s[i] - 'a';
		if(vec[c].size()) seg.push_back(mkp(vec[c].back(), i));
		vec[c].push_back(i); rk[i] = vec[c].size() - 1;
	}
	
	for(int i = 0; i < alf; i++) tmp[i] = 0;
	for(int i = 1; i <= n; i++) {
		int c = s[i] - 'a'; tmp[c] = i;
		for(int j = 0; j < alf; j++)
			lst[j][i] = tmp[j];
	}
	
	for(int i = 0; i < alf; i++) tmp[i] = n + 1;
	for(int i = n; i >= 1; i--) {
		int c = s[i] - 'a'; tmp[c] = i;
		for(int j = 0; j < alf; j++)
			nxt[j][i] = tmp[j];
	}
	
	
	memset(dplst, -1, sizeof(dplst));
	memset(dpnxt, -1, sizeof(dpnxt));
	sort(seg.begin(), seg.end(), cmp);
	for(int i = 0; i < seg.size(); i++) {
		int l = seg[i].fi, r = seg[i].se;
		if(r - l == 1) continue;
		dp[s[r] - 'a'][rk[r]] = dp_slow(l + 1, r - 1);
	}
		
//	cout<<"??";
	for(int c = 0; c < alf; c++)
		for(int i = 1; i < vec[c].size(); i++)
			dp[c][i] ^= dp[c][i - 1];
	return;
}
int main() {
	scanf("%s", s + 1); n = strlen(s + 1);
	init();
	int m; scanf("%d", &m);
	while(m--) {
		int l, r; scanf("%d%d", &l, &r);
		if(dp_fast(l, r) == 0) puts("Bob");
		else puts("Alice");
	}
	return 0;
}

标签:...,Manthan,int,Codefest,30,seg,Div,SG,dp
From: https://www.cnblogs.com/zdsrs060330/p/16854740.html

相关文章

  • Codeforces Round #610 (Div. 2) C
    C.PetyaandExamhttps://codeforces.com/contest/1282/problem/C考虑贪心先对于时间排序然后贪心我们可以不考那我们可以在此之前离开然后在离开之前这段时间多做......
  • np.divide()
    用例:numpy.divide(x1,x2,/,out=None,*,where=True,casting=‘same_kind’,order=‘K’,dtype=None,subok=True[,signature,extobj])=<ufunc‘true_divide’......
  • Codeforces Round #634 (Div. 3) E
    E2.ThreeBlocksPalindrome(hardversion)我们考虑一种最优构造对于一个数x我们肯定要的是他的前几个再最后几个中间选最多的一个数这样显然是最优的我们枚举x......
  • Codeforces Round #820 (Div. 3) A-G
    比赛链接A题解知识点:模拟时间复杂度\(O(1)\)空间复杂度\(O(1)\)代码#include<bits/stdc++.h>#definelllonglongusingnamespacestd;boolsolve(){......
  • Codeforces Round #611 (Div. 3) E
    E.NewYearParties对于最大值我们显然可以sort之后贪心一下即可正确性显然对于最小值我们发现会有三种情况一种是三个挨在一起一种是两个挨在一起还有一种就是......
  • div'可拖拽宽度
    <template><divclass="x-handle"@mousedown="mouseDown"></div></template><script>exportdefault{name:'HandleEvent',data(){return{lastX:''......
  • Codeforces Round #611 (Div. 3) D
    D.ChristmasTrees显然对于一个中间的点要是不能向两边最近的扩展我们直接判定他没有用处了这样我们就有了bfs的做法我们先把原点放进去要是能扩展我们显然可以直接......
  • Codeforces Round #667 (Div. 3) ABCD
    https://codeforces.com/contest/1409A.YetAnotherTwoIntegersProblem题目大意:k∈[1;10]我们每次可以选择a:=a+kora:=a−k问a要经历多少次操作变成b?input......
  • Educational Codeforces Round 81 (Rated for Div. 2) D
    D.SameGCDs对于题目所给的公式gcd(a,m)=gcd(a+x,m)由辗转相除我们把第二个式子变一下gcd((a+x)%m,m)x的取值范围为[0,m)(a+x)%m也是所以我们可以直接写成gcd(a,m)=g......
  • Codeforces Round #113 (Div. 2) E. Tetrahedron(dp/递推)
    https://codeforces.com/problemset/problem/166/E题目大意:给定一个正三角锥,最上面的顶点是D点,下面三个点分别标号为ABC给定n次,我们初始化在D点上,并且要求最后第n步也......