• 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); return 0;
    	}
    	for(int i = 1; i < N; i++) if(sum[0] - i == - sum[N]) {
    		printf("%d
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", p);
    		while(~p && q[p].l == L) {
    			R = q[p].r;
    //			printf("p = %d %d 
    ", p, Query(Root, 1, N));
    			ans[q[p--].p] = Query(Root, 1, N);
    		}
    //		printf("%d
    ", L);
    		if(p < 0) break;
    	}
    	
    	for(int i = 0; i < Q; i++)
    		printf("%d
    ", ans[i]);
    		
    	return 0;
    }
    

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

    F题推不出来...

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

    膜11个AK..

  • 相关阅读:
    1-6注册View Prism官网案例学习
    MVVM复习
    Prism常用类库翻译
    SqlHelper
    ADO.NET复习
    C#复习思维导图
    网络通信基础知识1
    网络通信
    Linux-线程同步之互斥锁
    linux-线程同步之信号量
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5006909.html
Copyright © 2020-2023  润新知