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..
51NOD 算法马拉松8的更多相关文章
- 51nod 算法马拉松 34 Problem D 区间求和2 (FFT加速卷积)
题目链接 51nod 算法马拉松 34 Problem D 在这个题中$2$这个质数比较特殊,所以我们先特判$2$的情况,然后仅考虑大于等于$3$的奇数即可. 首先考虑任意一个点对$(i, j)$ ...
- 随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3
先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率 假 ...
- 51Nod 算法马拉松21(迎新年)
这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过 ...
- 51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛
OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就 ...
- 51Nod 算法马拉松23 开黑记
惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...
- 51Nod 算法马拉松22 开黑记
这是一场惨烈的开黑大战,始于全机房开黑指望刷进rank前十拿钱的壮志,终于被各路神犇怒踩成rank20,差点200点头盾不保的落魄,想起将近一年前ad和zcg等学长挤进rank10的壮举,不由得唏嘘, ...
- 51nod算法马拉松 contest7
A题 链接:http://www.51nod.com/contest/problem.html#!problemId=1417 推荐链接:http://blog.csdn.net/a837199685 ...
- 51nod算法马拉松15
智力彻底没有了...看来再也拿不到奖金了QAQ... A B君的游戏 因为数据是9B1L,所以我们可以hash试一下数据... #include<cstdio> #include<c ...
- 51nod 算法马拉松18 B 非010串 矩阵快速幂
非010串 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 如果一个01字符串满足不存在010这样的子串,那么称它为非010串. 求长度为n的非010串的个数.(对1e9+7取模) ...
随机推荐
- Android TXT文件读写
package com.wirelessqa.helper; import java.io.FileInputStream; import java.io.FileOutputStream; impo ...
- C++ Primer 读书笔记 第1章
1.1 编写简单的C++程序 每个C++程序都必须包含一个main函数,因为main函数是系统执行入口,且main函数是唯一被系统显示调用的函数. 定义函数必须指定4个元素:返回类型.函数名.形参表. ...
- 不定高度实现垂直居中(兼容低版本ie)
css实现垂直居中的方法比较多,但是每种方法的缺陷也很明显,我尝试对其中一种方法进行了改良 先看原方法: <div class="parent"> <div cl ...
- validate 表单验证
转自博客园:http://www.cnblogs.com/easyinsc/archive/2009/02/27/1407826.html (1)required:true ...
- isalpha函数,判断字符是否是字母
头文件:<iostream> or <cctype> 在c语言中<ctype.h> 功能:判断一个字符是否是英文字符,是大写返回1,是小写返回2,不是英文字符返 ...
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...
- 建立一个ROS msg and srv
msg是一个描述ROS消息字段的简单的文本文件,它们经常用来为消息产生不同语言的源代码. srv文件描述一个服务,它由请求和响应两部分组成. msg文件被存储在一个包的msg目录下,srv文件被存储在 ...
- Labview学习之程序Web发布
Labview学习之程序Web发布 1. LabVIEW Web服务器 在LabVIEW开发环境中,自身带了一个已连接好的Web服务器.LabVIEW Web服务器除了与其他Web服务器一样能 ...
- Nginx启动报错:10013: An attempt was made to access a socket in a way forbidden
Nginx在win7,win2008下启动报错:bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a socket i ...
- hdu 3530 Subsequence 单调队列
题目链接 题目给出n个数, 一个下界m, 一个上界k, 让你求出最长的一段序列, 满足这段序列中的最大的数-最小的数<=k&&>=m, 输出这段长度. 可以维护两个队列, ...