Looksery Cup 2015 F

F - Yura and Developers

第一次知道单调栈搞出来的区间也能启发式合并。。。

你把它想想成一个树的形式, 可以发现确实可以启发式合并。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define PLI pair<LL, int>
#define ull unsigned long long
using namespace std;

const int N = 3e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;

int n, k, tot, a[N], stk[N], L[N], R[N], sum[N];
vector<int> num[1000007];

void add(int &a, int b) {
    a += b; if(a >= mod) a -= mod;
}
int cal(int x, int l, int r) {
    auto it1 = upper_bound(num[x].begin(), num[x].end(), r);
    auto it2 = lower_bound(num[x].begin(), num[x].end(), l);
    return it1 - it2;
}
int main() {
    scanf("%d%d", &n, &k);
    num[0].push_back(0);
    for(int i = 1; i <= n; i++) {
       scanf("%d", &a[i]);
       sum[i] = (sum[i-1]+a[i]%k)%k;
       num[sum[i]].push_back(i);
    }
    a[0] = a[n+1] = inf;
    stk[++tot] = 0;
    for(int i = 1; i <= n; i++) {
        while(tot && a[stk[tot]] < a[i]) tot--;
        L[i] = stk[tot];
        stk[++tot] = i;
    }
    tot = 0;
    stk[++tot] = n+1;
    for(int i = n; i >= 1; i--) {
        while(tot && a[stk[tot]] <= a[i]) tot--;
        R[i] = stk[tot];
        stk[++tot] = i;
    }
    LL ans = 0;
    for(int i = 1; i <= n; i++) {
        if(i - L[i] < R[i] - i) {
            for(int j = L[i]; j < i; j++)
                ans += cal((sum[j]+a[i])%k, i, R[i]-1);
        } else {
            for(int j = i; j < R[i]; j++) {
                ans += cal((sum[j]-(a[i]%k)+k)%k, L[i], i-1);
            }
        }
    }
    printf("%lld
", ans - n);
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/9916153.html