zoukankan      html  css  js  c++  java
  • 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
    ", (int)ans.size());
    	for(auto it = ans.begin(); it != ans.end(); ++it) {
    		printf("%d %d
    ", it->first, it->second);
    	}
    	return 0;
    }
    

    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
    ", 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
    ", ret);
    	}
    
    	return 0;
    }
    

      

  • 相关阅读:
    关于JsonObject的笔记
    addHeader() 与 setHeader() 区别
    BeanUtils.copyProperties(A,B)字段复制用法
    servletcontext的小结
    枚举笔记
    关于spring mvc接受前台参数的笔记
    关于session和cookie
    servlet学习
    tomcat到底是干嘛的
    .json文件报错 ,点进去是Expected value at 1:0
  • 原文地址:https://www.cnblogs.com/rolight/p/4260789.html
Copyright © 2011-2022 走看看