落下好多,趁着假期慢慢补吧。。
因为是一个森林,所以可以先找到所有的叶子节点,然后进行递推即可。开一个队列搞就好了。
#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;
}
这题没想出来,看了题解才会的。。
首先根据题意,很容易想到的是找到所有的最小区间,然后通过容斥原理求解。 并且在这之前可以先进行统计,如果有个数为奇数的字符种类数超过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;
}
原文:http://www.cnblogs.com/rolight/p/4260789.html