首页 > 代码库 > CodeForces R285 Div2

CodeForces R285 Div2

落下好多,趁着假期慢慢补吧。。

C. Misha and Forest

因为是一个森林,所以可以先找到所有的叶子节点,然后进行递推即可。开一个队列搞就好了。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <map>#include <set>#include <list>#include <queue>#include <stack>using namespace std;typedef long long LL;const int maxn = 1 << 17;int n, xsum[maxn], cnt[maxn];bool vis[maxn];set< pair<int, int> > ans;int main() {	scanf("%d", &n);	queue<int> q;	for(int i = 0; i < n; i++) {		scanf("%d%d", &cnt[i], &xsum[i]);		if(cnt[i] == 1) {			q.push(i);			vis[i] = true;		}	}	while(!q.empty()) {		int now = q.front(); q.pop();		if(cnt[now] == 0) continue;		int u = now, v = xsum[now];		if(u > v) swap(u, v);		ans.insert(make_pair(u, v));		xsum[xsum[now]] ^= now; 		cnt[xsum[now]]--;		if(cnt[xsum[now]] == 1 && !vis[xsum[now]]) {			q.push(xsum[now]); 			vis[xsum[now]] = true;		}	}	printf("%d\n", (int)ans.size());	for(auto it = ans.begin(); it != ans.end(); ++it) {		printf("%d %d\n", it->first, it->second);	}	return 0;}

D Misha and Permutations Summation

利用康拓展开得到展开之后进行相加,取模之后化简,观察一下很容易就发现做法了。。

中间可能要用一下线段树或者是树状数组来降低一下复杂度。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <map>#include <set>#include <list>#include <queue>#include <stack>using namespace std;typedef long long LL;const int maxn = 2e5 + 10;int p1[maxn], p1t[maxn], p2[maxn], p2t[maxn], n;int apt[maxn], ans[maxn];int C[maxn];int lowbit(int x) {	return x & (-x);}int init_bit() {	memset(C, 0, sizeof(C));}void addv(int pos, int x, int mx) {	while(pos <= mx) {		C[pos] += x;		pos += lowbit(pos);	}}int ask(int pos) {	int ret = 0;	while(pos > 0) {		ret += C[pos];		pos -= lowbit(pos);	}	return ret;}void calc(int arr[], int tar[], int len) {	init_bit();	for(int i = 0; i < len; i++) {		addv(i + 1, 1, len);	}	for(int i = len - 1; i >= 0; i--) {		tar[i] = ask(arr[i]);		addv(arr[i] + 1, -1, len);	}}int findk(int val, int mx) {	int l = 1, r = mx, ret = 1;	while(l <= r) {		int mid = (l + r) >> 1;		if(ask(mid) >= val) {			ret = mid;			r = mid - 1;		}		else {			l = mid + 1;		}	}	return ret;}void recalc(int arr[], int tar[], int len) {	init_bit();	for(int i = 0; i < len; i++) {		addv(i + 1, 1, len);	}	for(int i = len - 1; i >= 0; i--) {		tar[i] = findk(arr[i] + 1, len) - 1;		addv(tar[i] + 1, -1, len);	}}int main() {	scanf("%d", &n);	for(int i = 0; i < n; i++) {		scanf("%d", &p1[i]);	}	reverse(p1, p1 + n);	calc(p1, p1t, n);	for(int i = 0; i < n; i++) {		scanf("%d", &p2[i]);	}	reverse(p2, p2 + n);	calc(p2, p2t, n);	for(int i = 0; i < n; i++) {		apt[i] += p1t[i] + p2t[i];		apt[i + 1] += apt[i] / (i + 1);		apt[i] %= (i + 1);	}	recalc(apt, ans, n);	for(int i = n - 1; i >= 0; i--) {		printf("%d ", ans[i]);	}	puts("");	return 0;}

 E Misha and Palindrome Degree

这题没想出来,看了题解才会的。。

首先根据题意,很容易想到的是找到所有的最小区间,然后通过容斥原理求解。 并且在这之前可以先进行统计,如果有个数为奇数的字符种类数超过1的话可以直接判不成立。

首先找到最大的i使得 任意k < i 有 a[i] = a[n - i + 1], 不难发现最小区间必然有一个边界是i 或者 n - i + 1

然后分别固定左边界和右边界,然后来找最小区间的位置。可以发现这里是具有单调性的,所以可以用二分来降低复杂度,二分最小区间的长度。

至于这个区间是否合法可以用O(n)来判断。

对于每一个位置i,有以下几种情况,并且会以以下的次序出现(以左区间端点固定为例),并且设当前区间是[l, r]

首先是  i < l, n - i + 1 > r,此时必然有a[i] = a[n - i + 1]成立,可以不做判断

然后是 r >= i >= l, n - i + 1 > r,或者是i < l,n - i + 1 <= r, 此时区间中必须要有大于等于1个对应字符,否则不成立,这里要在之前做一些统计并且判断

然后是 l <= i <= n - i + 1 <= r,设这里的i为i0,必然有当i < i0外面那部分都是回文的,在进行二分之前判断过字符串必定可以构成回文的,所以此时剩下的字符必然也可以构成回文,所以不必判断。

最后是 r < i <= n - i + 1,这里要判断a[i]是否和a[n - i + 1]相等。

之后容斥原理随意搞即可。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <map>#include <set>#include <list>#include <queue>#include <stack>//using namespace std;typedef long long LL;const int maxn = 1e5 + 10;int a[maxn], n, cl, cr, count[maxn], odd;bool check(int lpos, int rpos) {	memset(count, 0, sizeof(count));	for(int i = lpos; i <= rpos; i++) {		count[a[i]]++;	}	for(int i = 1; i < n - i + 1; i++) {		bool inL = (i >= lpos && i <= rpos);		bool inR = (n - i + 1 >= lpos && n - i + 1 <= rpos);		if(inL && inR) continue;		else if(inL) {			if(--count[a[n - i + 1]] < 0) return false;		}		else if(inR) {			if(--count[a[i]] < 0) return false;		}		else {			if(a[i] != a[n - i + 1]) return false;		}	}	return true;}LL calc(int pos) {	int l = pos, r = n, tar;	while(l <= r) {		int mid = (l + r) >> 1;		if(check(pos, mid)) {			tar = mid;			r = mid - 1;		}		else {			l = mid + 1;		}	}	return (LL)pos * (LL)(n - tar + 1);}int main() {	scanf("%d", &n);	for(int i = 1; i <= n; i++) {		scanf("%d", &a[i]);		count[a[i]]++;	}	for(int i = 1; i <= n; i++) {		if(count[i] & 1) {			odd++;		}	}	cl = 1;	cr = n;	while(cl <= cr && a[cl] == a[cr]) {		cl++; cr--;	}	if(cl > cr) {		LL ret = (LL)n * (LL)(n - 1) / 2 + n;		printf("%I64d\n", ret);	}	else if(odd > 1) {		puts("0");	}	else {		LL ret = -(LL)cl * (LL)(n - cr + 1);		ret += calc(cl);		std::reverse(a + 1, a + 1 + n);		ret += calc(cl);		printf("%I64d\n", ret);	}	return 0;}

  

 

CodeForces R285 Div2