51NOD 算法马拉松8

题目戳这里:51NOD算法马拉松8

某天晚上kpm在玩OSU!之余让我看一下B题...然后我就被坑进了51Nod...

A.还是01串

水题..怎么乱写应该都可以。记个前缀和然后枚举就行了.时间复杂度O(N)

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn = 1000009;

char s[maxn];
int sum[maxn], N;

int main() {
//	freopen("test.in", "r", stdin);
	
	memset(sum, 0, sizeof sum);
	
	scanf("%s", s);
	N = strlen(s);
	sum[N] = 0;
	for(int i = N; i--; )
		sum[i] = sum[i + 1] + (s[i] == '1');
	if(!sum[0]) {
		puts("0"); return 0;
	}
	if(sum[0] == N) {
		printf("%d\n", N); return 0;
	}
	for(int i = 1; i < N; i++) if(sum[0] - i == - sum[N]) {
		printf("%d\n", i); return 0;
	}
	puts("-1");
	
	return 0;
}

B.差和问题

题目大意:维护一个集合S,支持加入/删除元素v, 询问S里面的元素两两之差绝对值之和.N,Q≤100000.

拆掉绝对值, 每次我们加入或者删除x时,用平衡树维护x对答案的贡献即可,时间复杂度O(NlogN)

(PS.官方题解好像是离散化+树状数组..常数应该小一点..我一开始没加读入优化还被卡TLE了2个点..)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<queue>

using namespace std;

typedef long long ll;

const int maxn = 200009;

int read() {
	char c = getchar();
	int ret = 0;
	for(; !isdigit(c); c = getchar());
	for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
	return ret;
}

struct Node {
	
	Node* ch[2];
	ll sum;
	int r, v, s;
	
	void upd() {
		s = ch[0]->s + ch[1]->s + 1;
		sum = ch[0]->sum + ch[1]->sum + v;
	}
	
} pool[maxn], *Null, *Root;
queue<Node*> q;

Node* newNode(int v) {
	Node* t = q.front(); q.pop();
	t->s = 1;
	t->v = v;
	t->r = rand();
	t->ch[0] = t->ch[1] = Null;
	return t;
}

void InitTreap() {
	for(int i = 1; i < maxn; i++)
		q.push(pool + i);
	Root = Null = pool;
	Null->sum = 0;
	Null->s = 0;
	Null->ch[0] = Null->ch[1] = Null;
}

void Rotate(Node*&t, int d) {
	Node* o = t->ch[d ^ 1];
	t->ch[d ^ 1] = o->ch[d];
	o->ch[d] = t;
	t->upd(); o->upd();
	t = o;
}

void Insert(Node*&t, int v) {
//	printf("%d\n", v);
	if(t == Null) {
		t = newNode(v);
	} else {
		int d = (v > t->v);
		Insert(t->ch[d], v);
		if(t->ch[d]->r > t->r)
			Rotate(t, d ^ 1);
	}
	t->upd();
}

void Delete(Node*&t, int v) {
	int d = (t->v == v ? -1 : (v > t->v));
	if(!~d) {
		if(t->ch[0] != Null && t->ch[1] != Null) {
			int _d = (t->ch[0]->r > t->ch[1]->r);
			Rotate(t, _d);
			Delete(t->ch[_d], v);
		} else {
			q.push(t);
			t = (t->ch[0] == Null ? t->ch[1] : t->ch[0]);
		}
	} else 
		Delete(t->ch[d], v);
	if(t != Null)
		t->upd();
}

ll ans = 0, sum = 0;
int sz = 0, N, Q;

void update(int v, bool typ) {
	int _sz = 0;
	ll _sum = 0;
	for(Node* t = Root; t != Null; ) {
		if(t->v <= v)
			_sz += t->ch[0]->s + 1, _sum += t->ch[0]->sum + t->v, t = t->ch[1];
		else
			t = t->ch[0];
	}
	
	if(typ) {
//		printf("%d %d %d %lld %lld\n", v, sz, _sz, sum, _sum);
		ans += ll(v) * _sz - _sum;
		ans += sum - _sum - ll(v) * (sz - _sz);
		sz++, sum += v;
	} else {
		ans -= ll(_sz) * v - _sum;
		ans -= sum - _sum - ll(v) * (sz - _sz);
		sz--, sum -= v;
	}
}

bool Find(Node* t, int v) {
	if(t == Null) return false;
	if(t->v == v) return true;
	return v < t->v ? Find(t->ch[0], v) : Find(t->ch[1], v);
}

int main() {
//	freopen("test.in", "r", stdin);
	
	InitTreap();
	
	N = read(); Q = read();
	for(int i = 0; i < N; i++) {
		int v = read();
		update(v, 1);
		Insert(Root, v);
	}
	while(Q--) {
		int opt = read();
		if(opt == 3)
			printf("%lld\n", ans);
		else {
			int v = read();
			if(opt == 1) {
				update(v, 1);
				Insert(Root, v);
			} else {
				if(!Find(Root, v)) {
					puts("-1"); continue;
				}
				update(v, 0);
				Delete(Root, v);
			}
		}
	}		
	
	return 0;
}

C.找朋友

题目大意:给两个长度为N的数列A、B,一个有m个元素的集合K.Q个询问[l,r]内满足|Bi-Bj|∈K 的最大Ai+Aj.N,Q≤100000,M≤10

一开始不太会做...用莫队的话是O(M*N^1.5)..会TLE..因为至多有M*N对满足题意的数对,我们可以直接考虑他们对答案的贡献...那么离线将询问排序然后线段树维护就可以了,时间复杂度O(MNlogN)

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>

using namespace std;

const int maxn = 100009;

int read() {
	char c = getchar();
	int ret = 0;
	for(; !isdigit(c); c = getchar());
	for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
	return ret;
}

int N, Q, M, A[maxn], B[maxn], _B[maxn], K[maxn], ans[maxn];

struct QUERY {
	
	int l, r, p;
	
	void Read(int x) {
		l = read(); r = read(); p = x;
	}
	
	bool operator < (const QUERY &o) const {
		return l < o.l;
	}
	
} q[maxn];

void Init() {
	memset(_B, -1, sizeof _B);
	N = read(); Q = read(); M = read();
	for(int i = 1; i <= N; i++) A[i] = read();
	for(int i = 1; i <= N; i++) _B[B[i] = read()] = i;
	for(int i = 0; i < M; i++) K[i] = read();
	for(int i = 0; i < Q; i++) q[i].Read(i);
	sort(q, q + Q);
//	for(int i = 0; i < Q; i++)
//		printf("[ %d , %d ] %d\n", q[i].l, q[i].r, q[i].p);
}

int L, R, V;

struct Node {
	
	Node *l, *r;
	int v;
	
	Node() : v(0) {
		l = r = NULL;
	}
	
	void upd() {
		if(l)
			v = max(l->v, r->v);
	}
	
} pool[maxn << 1], *pt = pool, *Root;

void Build(Node* t, int l, int r) {
	if(l == r)
		return;
	int m = (l + r) >> 1;
	Build(t->l = pt++, l, m);
	Build(t->r = pt++, m + 1, r);
}
	
void Modify(Node* t, int l, int r) {
	if(l == r)
		t->v = max(t->v, V);
	else {
		int m = (l + r) >> 1;
		R <= m ? Modify(t->l, l, m) : Modify(t->r, m + 1, r);
		t->upd();
	}
}

int Query(Node* t,int l, int r) {
	if(L <= l && r <= R)
		return t->v;
	int m = (l + r) >> 1;
	return max(L <= m ? Query(t->l, l, m) : 0, m < R ? Query(t->r, m + 1, r) : 0);
}

int main() {
//	freopen("test.in", "r", stdin);
//	freopen("test.out", "w", stdout);
	
	Init();
	
	Build(Root = pt++, 1, N);
	
	int p = Q - 1;
	for(L = N; L; L--) {
//		printf("%d\n", L);
		int &v = B[L];
		for(int j = 0; j < M; j++) {
			if(v - K[j] >= 1 && ~_B[v - K[j]] && _B[v - K[j]] > L) {
				V = A[L] + A[R = _B[v - K[j]]];
//				printf("%d\n", V);
				Modify(Root, 1, N);
			}
			if(v + K[j] <= N && ~_B[v + K[j]] && _B[v + K[j]] > L) {
				V = A[L] + A[R = _B[v + K[j]]];
				Modify(Root, 1, N);
			}
		}
//		printf("%d\n", p);
		while(~p && q[p].l == L) {
			R = q[p].r;
//			printf("p = %d %d \n", p, Query(Root, 1, N));
			ans[q[p--].p] = Query(Root, 1, N);
		}
//		printf("%d\n", L);
		if(p < 0) break;
	}
	
	for(int i = 0; i < Q; i++)
		printf("%d\n", ans[i]);
		
	return 0;
}

 

D,E,F都不会写...D题完全没什么思路.E题感觉可以搞但是因为要输出1~N的就不会了,O(N^2)妥妥的TLE啊...

F题推不出来...

这是E题..假如你会的话请评论...

 

膜11个AK..

 

posted @ 2015-11-30 13:28  JSZX11556  阅读(234)  评论(0编辑  收藏  举报