CF817
AB略
CF817C
CF817C题意
问 [ 1 , n ] [1,n] [1,n] 中有多少个数 x x x 满足 x x x - 各位数字之和 ⩾ s \geqslant s ⩾s
CF817C题解
水蓝题。
不难发现,对于一个数字
x
x
x 对答案的贡献
- x < s x<s x<s:一定不成立
- s ≤ x ≤ s + 9 × 18 s\le x\le s+9\times18 s≤x≤s+9×18:特殊判断下就好、
- s + 9 × 18 < x s+9\times18<x s+9×18<x:一定成立
所以说这题是水题嘛(
CF817C代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
int n, s;
bool check(int x){
int tmp = x, res = 0;
while(tmp){res += tmp % 10;tmp /= 10;}
return x - res >= s;
}
signed main(){
n = read(); s = read();int ans = max(n - s - 9 * 18,0LL);
for(int i = 0;i <= 9 * 18 && s + i <= n;i++){if(check(s + i))ans++;}
printf("%lld\n",ans);
return 0;
}
CF817D
CF817D题意
定义不平衡值是数组的最大值减去最小值,求一个数组的所有子数组的不平衡值的总和。
CF817D题解
答案=所有子数组各自的最大值之和-所有子数组各自的最小值之和
先想最大值之和怎么求,最小值同理。
考虑一个数字
a
i
a_i
ai 对于答案的贡献。
如果设
L
i
,
R
i
L_i,R_i
Li,Ri 表示
[
L
i
,
R
i
]
[L_i,R_i]
[Li,Ri] 是使得
a
i
a_i
ai 最大的最长区间。
那么
a
i
a_i
ai 的贡献就是
(
i
−
L
i
+
1
)
∗
(
R
i
−
i
+
1
)
∗
a
i
(i-L_i+1)*(R_i-i+1)*a_i
(i−Li+1)∗(Ri−i+1)∗ai。
然后这玩应可以单调栈求。
然后注意下重复元素的处理就没了。
CF817D代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f= -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e6 + 10;
int a[maxn], n;
int L[maxn], R[maxn];
int l[maxn], r[maxn];
int ans;
stack<pair<int,int> > stk;
signed main(){
n = read();for(int i = 1;i <= n;i++)a[i] = read();
a[0] = a[n + 1] = 0x3f3f3f3f3f3f3f3f;
while(!stk.empty())stk.pop();stk.push(make_pair(a[0],0));
for(int i = 1;i <= n;i++){
while(!stk.empty() && stk.top().first < a[i])stk.pop();
L[i] = stk.top().second + 1;
stk.push(make_pair(a[i],i));
}
while(!stk.empty())stk.pop();stk.push(make_pair(a[n + 1],n + 1));
for(int i = n;i;i--){
while(!stk.empty() && stk.top().first <= a[i])stk.pop();
R[i] = stk.top().second - 1;
stk.push(make_pair(a[i],i));
}
for(int i = 1;i <= n;i++){l[i] = L[i];r[i] = R[i];}
// for(int i = 1;i <= n;i++){printf("i=%lld : L=%lld R=%lld\n",i,L[i],R[i]);}
a[0] = a[n + 1] = -1;
while(!stk.empty())stk.pop();stk.push(make_pair(a[0],0));
for(int i = 1;i <= n;i++){
while(!stk.empty() && stk.top().first > a[i])stk.pop();
L[i] = stk.top().second + 1;
stk.push(make_pair(a[i],i));
}
while(!stk.empty())stk.pop();stk.push(make_pair(a[n + 1],n + 1));
for(int i = n;i;i--){
while(!stk.empty() && stk.top().first >= a[i])stk.pop();
R[i] = stk.top().second - 1;
stk.push(make_pair(a[i],i));
}
for(int i = 1;i <= n;i++){
ans += (a[i] * ((i - l[i] + 1) * (r[i] - i + 1) - (i - L[i] + 1) * (R[i] - i + 1)));
}
// for(int i = 1;i <= n;i++){printf("i=%lld : L=%lld R=%lld\n",i,L[i],R[i]);}
printf("%lld\n",ans);
return 0;
}
CF817E
CF817E题意
有一个初始为空的可重集 S S S。现在有 Q Q Q 次操作,每次操作有 3 3 3 种类型,分别是:
-
1 , p i 1,p_i 1,pi,把 p i p_i pi 加入 S S S。
-
2 , p i 2,p_i 2,pi,将 p i p_i pi 从 S S S 中删除,保证在删除前 p i p_i pi 已经在 S S S 中。
-
3 , p i , l i 3,p_i,l_i 3,pi,li,询问 S S S 中有多少个数按位异或上 p i p_i pi 的结果小于 l i l_i li。
CF817E题解
这玩应看着就是 01 t r i e 01trie 01trie,然后就写吧。:)
CF817E代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f= -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e5 + 10;
int q;
int trie[maxn * 80][2], tot = 1;
int cnt[maxn * 80];
void update(int x,int add){
int u = 1;
for(int i = 31;i + 1;i--){
bool v = x & (1 << i);
if(!trie[u][v])trie[u][v] = ++tot;
cnt[trie[u][v]] += add;
u = trie[u][v];
}
}
int query(int x,int l){
int u = 1, res = 0;
for(int i = 31;i + 1;i--){
bool v = x & (1 << i);
if(l & (1 << i))res += cnt[trie[u][v]],u = trie[u][v ^ 1];
else u = trie[u][v];
}
return res;
}
signed main(){
q = read();int opt, u;
for(int i = 1;i <= q;i++){
opt = read(); u = read();
if(opt == 1)update(u, 1);
if(opt == 2)update(u,-1);
if(opt == 3)printf("%lld\n",query(u,read()));
}
return 0;
}
CF817F
CF817F题意
维护一个集合 S S S,需要你支持下面三种操作
- 补齐 [ l , r ] [l,r] [l,r] 中所有 S S S 没有的数字
- 删除 [ l , r ] [l,r] [l,r] 中所有 S S S 中有的数字
- 删除 [ l , r ] [l,r] [l,r] 中所有 S S S 中有的数字,同时填入之前没有的数字
每次操作后都要求给出这个集合的
M
E
X
MEX
MEX 值。
注意,这里的
M
E
X
MEX
MEX 是最小的
S
S
S 中没有的正整数,不是非负整数。
操作数
n
≤
1
0
5
n\le 10^5
n≤105,值域
≤
1
0
18
\le10^{18}
≤1018。
CF817F题解
这套题怎么两道数据结构?!
这道题怎么还这么毒瘤?!!(
首先先离散化,将所有
l
i
,
r
i
,
l
i
−
1
,
r
i
+
1
l_i,r_i,l_i-1,r_i+1
li,ri,li−1,ri+1 填入离散化数组(
l
i
−
1
l_i-1
li−1 是可能的最小解,
r
i
+
1
r_i+1
ri+1 保证有解)
然后发现这玩应就是维护一个
01
01
01 序列。
操作按照题意做即可,不过需要注意
p
u
s
h
d
o
w
n
pushdown
pushdown 的写法。
查询的话在线段树上二分,每次如果左儿子有
0
0
0,就跳左儿子,否则右儿子。
然后就没了~~~~~~吗?
wrong answer on test 15
突然发现一个问题,如果所有的操作都没有包括
1
1
1,那么答案永远是
1
1
1,但是由于刚刚的做法离散化数组没带
1
1
1,于是就WA了我不会告诉你我WA了几发的
这下就真没了(
CF817F代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0 , f =1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e5 + 10;
int n, tot;
int tag[maxn], x[maxn], y[maxn];
vector<int> vec;
struct Segment_Tree{
int mxxxx;
struct node{
int sum, tag, l, r;//sum:count 1
node(int sum = 0,int l = 0,int r = 0,int tag = 0):sum(sum),l(l),r(r),tag(tag){}
}d[maxn << 4];
node mergenode(node l,node r){return node(l.sum + r.sum,l.l,r.r);}
void gettag(int p,int t){
if(p > mxxxx || d[p].r == 0)return;
if(t == 1){d[p].sum = d[p].r - d[p].l + 1;}
if(t == 2){d[p].sum = 0;}
if(t == 3){d[p].sum = d[p].r - d[p].l + 1 - d[p].sum;}
d[p].tag = t;
}
void build(int l,int r,int p){
if(l == tot)mxxxx = p << 1;
if(l == r){d[p] = node(0,l,r,0);return;}
int mid = l + r >> 1;
build(l,mid,p << 1);build(mid + 1, r ,p << 1 | 1);
d[p] = mergenode(d[p << 1],d[p << 1 | 1]);
}
void pushdown(int p){
if(p > mxxxx || d[p].r == 0)return;
if(d[p].tag && (d[p].r != d[p].l)){
if(d[p].tag == 3){
if(d[p << 1].tag == 1 || d[p << 1].tag == 2){gettag(p << 1,d[p << 1].tag ^ 3);}
else{d[p << 1].tag ^= 3;d[p << 1].sum = d[p << 1].r - d[p << 1].l + 1 - d[p << 1].sum;}
if(d[p << 1 | 1].tag == 1 || d[p << 1 | 1].tag == 2){gettag(p << 1 | 1,d[p << 1 | 1].tag ^ 3);}
else{d[p << 1 | 1].tag ^= 3;d[p << 1 | 1].sum = d[p << 1 | 1].r - d[p << 1 | 1].l + 1 - d[p << 1 | 1].sum;}
}
else {
// if(d[p << 1].tag == 3)pushdown(p << 1);
gettag(p << 1,d[p].tag);
// if(d[p << 1 | 1].tag == 3)pushdown(p << 1 | 1);
gettag(p << 1 | 1,d[p].tag);
}
d[p].tag = 0;
}
}
void update(int l,int r,int s,int t,int p,int tags){
if(s <= l && r <= t){pushdown(p);gettag(p,tags);return;}
int mid = l + r >> 1;pushdown(p);
if(s <= mid)update(l,mid,s,t,p << 1,tags);
if(mid < t)update(mid + 1,r,s,t,p << 1 | 1,tags);
d[p] = mergenode(d[p << 1],d[p << 1 | 1]);
// printf("l=%lld r=%lld p=%lld sum=%lld\n",l,r,p,d[p].sum);
}
int query(int l,int r,int p){
if(l == r)return l;
int mid = l + r >> 1;pushdown(p);
// printf("l=%lld r=%lld p=%lld sum=%lld\n",l,r,p,d[p].sum);
// printf("lsum=%lld,rsum=%lld\n",d[p << 1].sum,d[p << 1 | 1].sum);
if(d[p << 1].sum < d[p << 1].r - d[p << 1].l + 1)
return query(l,mid,p << 1);
else return query(mid + 1,r,p << 1 | 1);
}
void update(int s,int t,int tags){update(1,tot,s,t,1,tags);}
int query(){return query(1,tot,1);}
}tree;
signed main(){
n = read();vec.push_back(-1);
for(int i = 1;i <= n;i++){
tag[i] = read(); x[i] = read(); y[i] = read();
vec.push_back(x[i]);vec.push_back(y[i]);
vec.push_back(y[i] + 1);if(x[i] != 1)vec.push_back(x[i] - 1);
}
sort(vec.begin(),vec.end());vec.erase(unique(vec.begin(),vec.end()),vec.end());tot = vec.size() - 1;
// printf("tot=%lld : ",tot);
// for(int i : vec)printf("%d ",i);puts("");
if(vec[1] > 1){for(int i = 1;i <= n;i++)puts("1");return 0;}
tree.build(1,tot,1);
for(int i = 1;i <= n;i++){
x[i] = lower_bound(vec.begin(),vec.end(),x[i]) - vec.begin();
y[i] = lower_bound(vec.begin(),vec.end(),y[i]) - vec.begin();
// printf("%lld %lld %lld\n",x[i],y[i],tag[i]);
tree.update(x[i],y[i],tag[i]);
printf("%lld\n",vec[tree.query()]);
// for(int i = 1;i <= 13;i++){printf("i=%lld,l=%lld,r=%lld,sum=%lld,tag=%lld\n",i,tree.d[i].l,tree.d[i].r,tree.d[i].sum,tree.d[i].tag);}
}
return 0;
}