CF817

CF817

AB略

CF817C

link

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 sxs+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

link

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 (iLi+1)(Rii+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

link

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

link

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 n105,值域 ≤ 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,li1,ri+1 填入离散化数组( l i − 1 l_i-1 li1 是可能的最小解, 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;
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值