题目大意
给定一个长度为 n 的排列 p。定义一个数组为 k-exquisite 当且仅当:
-
该数组至少包含两个元素
-
任意两个相邻元素的差的绝对值至少为 k
对于每个 k(从 1 到 n-1),需要求出排列 p 中有多少个子数组是 k-exquisite 的。
输入格式:
输出格式:
对于每个测试用例,输出 n-1 个整数,第 i 个整数表示 i-exquisite 子数组的个数。
数据范围:
-
时间限制:2 秒
-
内存限制:256 MB
-
所有测试用例的 n 之和不超过 2×10⁵
思路讲解
感觉比 D,B 简单。
如果只需要求这个 k-exquisite 子数组的个数,那就直接双指针,不过这波是要求这个 i-exquisite 子数组的个数。
我们想到,其实这个无非就是把整个数组切成了几段,我们可以采用做减法的方式,去解决这个问题。具体来讲,设我们所求的这个子数组参数为 k,一个差值 Δ,k≤Δ 可以直接跨过去,k>Δ 就不可以。

不难想到,我们可以对这个差值进行排序,或者一种更方便的实现是使用这个 map,并在 set 中存放分隔点,初始设置为这个 0,N(其实这里是一个坑点,不要选成 0,N+1 了,因为我们的分隔点采用前向点,最大为 N-1,因此哨兵应该选 N)。不难发现,设我们的新分隔点为 pos,set 数组中第一个比我们小的数字是 low,第一个比我们大的数字是 high,我们所需要减去的值就是 (pos−low)×(high−pos),即 low 区有 (pos−low) 种选择,high 区是 (high−pos) 种选择,使用乘法原理乘起来即可。
1 2 3 4 5 6 7 8 9 10 11
| set<ll> st={0,N}; for (int i=1;i<=N-1;++i) { cout<<ans<<" "; for (auto pos:mp_diff_pos[i]) { ll low=get_lower(pos); ll high=*st.lower_bound(pos); ll minus=(pos-low)*(high-pos); ans-=minus; st.insert(pos); } }
|
AC代码
AC
https://codeforces.com/contest/2184/submission/357897043
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
#include <bits/stdc++.h> #include <ranges> #define all(vec) vec.begin(),vec.end() #define lson(o) (o<<1) #define rson(o) (o<<1|1) #define SZ(a) ((long long) a.size()) #define debug(var) cerr << #var <<":"<<var<<"\n"; #define cend cerr<<"\n-----------\n" #define fsp(x) fixed<<setprecision(x)
using namespace std;
using ll = long long; using ull = unsigned long long; using DB = double; using LD = long double;
using CD = complex<double>;
static constexpr ll MAXN = (ll)1e6+10, INF = (1ll<<61)-1; static constexpr ll mod = 998244353; static constexpr double eps = 1e-8; const double pi = acos(-1.0);
ll lT;
void Solve() { ll N; cin >> N; vector<ll> P(N);
for (int i=0;i<N;++i) { cin>>P[i]; } map<ll,vector<ll>> mp_diff_pos; for (int i=0;i<N-1;++i) { ll diff=abs(P[i]-P[i+1]); mp_diff_pos[diff].push_back(i+1); } ll ans=N*(N-1)/2; set<ll> st={0,N}; auto get_lower=[&](ll x) { auto it=st.lower_bound(x); --it; return *it; }; for (int i=1;i<=N-1;++i) { cout<<ans<<" "; for (auto pos:mp_diff_pos[i]) { ll low=get_lower(pos); ll high=*st.lower_bound(pos); ll minus=(pos-low)*(high-pos); ans-=minus; st.insert(pos); } } cout<<"\n"; }
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin >> lT; while(lT--) Solve(); return 0; }
|
心路历程(WA,TLE,MLE……)