zoukankan      html  css  js  c++  java
  • 《河南省赛C》

    https://ac.nowcoder.com/acm/contest/17148/C。

    这题挺好的。

    其实一开始已经差不多想到了。

    前缀和+容斥。

    但是这个容斥一直没想到怎么做,就硬冲线段树去了。

    这里其实有一个很重要的信息。

    假设L点的右边有解的位置是r。

    那么对于所有L左边的点,他们的有解位置肯定<=r。

    那么我们查询的时候。

    对于区间[L,r]:先找到r的左有解位置pos.

    那么对于[L,pos]里的点,他们的右有解位置肯定<=r。

    那么我们把以他们为开头~n里的所有值加上(这里用前缀和来处理即可),然后再 - (pos - L + 1) * (n - r)即可。

    因为这个信息的存在,我们减去的区间里的右有解位置都肯定<=r。不会存在减去负的情况,也满足正确性。

    对于sum[i]表示以i ~ n里面满足条件的序列数。

    我们先尺取维护出L[i] - i的最大左有解点,r[i] - i的最小有解点。

    那么sum[i]就可以走一遍前缀和取出来。

    这里还有个小坑。

    如果下面异或处理的L和赋值的一样,那么在第一个L异或之后,L就变了。

    所以要用不同的变量。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,LL> pii;
    const int N = 1e6 + 5;
    const int M = 1e5 + 5;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int n,m,k,a[N],lp[N],rp[N];
    LL sum[N];
    deque<int> Q;
    map<int,int> mp;
    LL solve(int L,int r) {
        int pos = lp[r];
        if(pos < L) return 0;
        LL ma = sum[L] - sum[pos + 1];
        return ma - 1LL * (pos - L + 1) * (n - r);
    }
    int main() {
        n = read(),m = read(),k = read();
        for(int i = 1;i <= n;++i) a[i] = read();
        int now = 0,cnt = 0;
        while(now <= n) {
            if(cnt < k) {
                if(now == n) break;
                int pre = 0;
                if(Q.size() > 0) pre = Q.back();
                Q.push_back(++now);
                mp[a[now]]++;
                if(mp[a[now]] == 1) {
                    cnt++;
                    if(cnt == k && Q.size() > 0) {
                        rp[Q.front()] = Q.back();
                        lp[Q.back()] = Q.front();
                    }
                }
                else if(Q.size() > 0){
                    lp[Q.back()] = lp[pre];
                }
            }
            else {
                int x = Q.front();
                Q.pop_front();
                mp[a[x]]--;
                if(mp[a[x]] == 0) cnt--;
                if(cnt == k && Q.size() > 0) {
                    rp[Q.front()] = Q.back();
                    lp[Q.back()] = Q.front();
                }
            }
        }
        for(int i = 1;i <= n;++i) {
            if(a[i] == a[i - 1]) {
                rp[i] = rp[i - 1];
                lp[i] = lp[i - 1];
            }
        }
        for(int i = n;i >= 1;--i) {
            sum[i] = sum[i + 1];
            if(rp[i] != 0) sum[i] += 1LL * (n - rp[i] + 1);
        }
     //   for(int i = 1;i <= n;++i) printf("L[%d] is %d r[%d] is %d sum[%d] is %lld
    ",i,lp[i],i,rp[i],i,sum[i]);
        LL ans = 0;
        while(m--) {
            int LL,rr;LL = read(),rr = read();
            int L = min(LL ^ ans,rr ^ ans) + 1;
            int r = max(LL ^ ans,rr ^ ans) + 1;
            ans = solve(L,r);
            printf("%lld
    ",ans);
        }
    
        system("pause");
        return 0;
    }
    /*
    10 5 3
    1 2 3 4 5 6 7 8 9 10
    1 5
    2 6
    3 7
    1 5
    
    */
    View Code
  • 相关阅读:
    40_接口类型的使用
    39_方法值和方法表达式
    38_方法的重写
    37_匿名字段方法的继承
    36_方法集的使用
    文件方式实现完整的英文词频统计实例
    组合数据类型练习,英文词频统计实例上
    英文词频统计预备,组合数据类型练习
    凯撒密码、GDP格式化输出、99乘法表
    字符串基本操作‘’
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/14828970.html
Copyright © 2011-2022 走看看