Codeforces Round 1032 (Div. 3) F. Yamakasi

F. Yamakasi

题目: F. Yamakasi

思路:
题目问和为 s 且区间最大值为 x 的区间数量,不难想到以 x 为遍历的主角,以两边不超过 x 的范围为边界,在这个范围里去下手。找边界(左右两边第一个大于/大于等于 x 的位置)为单调栈模板。

  1. 预处理好每个 x 的范围后,对于合法范围 [l, r] 内的点,记 sum[] 为前缀和,i 遍历 x 的位置 idr,即是要找前缀和为\(sum[j-1] = sum[i] - s\)的位置 j-1(这样区间范围才是 ji)。这里二分找到第一个大于等于 l-1 的位置 L,第一个大于等于 id 的位置 R,贡献就是 R - L

  2. 这样需要注意一个问题,当有多个 x 的时候,会存在重复的问题,比如 ... x ... x ... x 时,对于第二个 x,可能选择区间的时候会选到第三个 x,到时第三个 x 又会选到第二个 x。针对这种情况,做过的题目也不少,选择区间一闭一开即可,我这里采用左边界找第一个大于等于 x 的,右边界找第一个大于 x 的,这样就不会有重复性问题了。


代码
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define endl '\n'
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 2e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+ 1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };

ll a[maxn];
ll l[maxn], r[maxn], sum[maxn];
ll n,s,x;
map<ll,vector<ll> > Map;
void init()
{
  Map.clear();
  stack<ll> s;
  Map[0].pb(0);
  rep(i,1,n)
  {
    while(s.size()&&a[s.top()]<=a[i]) s.pop();
    if(s.size()) l[i] = s.top();
    else l[i] = 0;
    s.push(i);
    sum[i] = sum[i-1] + a[i];
    Map[sum[i]].pb(i);
  }

  while(s.size()) s.pop();

  per(i,n,1)
  {
    while(s.size()&&a[s.top()]<a[i]) s.pop();
    if(s.size()) r[i] = s.top();
    else r[i] = n+1;
    s.push(i);
  }

}

ll cal(ll l, ll id, ll r)
{
  ll ans = 0;
  rep(i,id,r)
  {
    ll k = sum[i] - s; // j-1
    if(!Map.count(k)) continue;
    ll id1 = lower_bound(Map[k].begin(),Map[k].end(),l-1) - Map[k].begin();
    ll id2 = lower_bound(Map[k].begin(),Map[k].end(),id) - Map[k].begin();
    ans += id2-id1;
  }
  return ans;
}

void sol()
{
  n = read(), s = read(), x = read();
  rep(i,1,n) a[i] = read();
  init();

  ll nxt = 0, ans = 0;
  rep(i,1,n)
  {
    if(i<=nxt||a[i]!=x) continue;
    ans += cal(l[i]+1,i,r[i]-1);
    nxt = r[i]-1;
  }
  printf("%lld\n",ans);
}

int main()
{
    int kase;
    cin>>kase;
    while(kase--) sol();
    return 0;
}
}
posted @ 2025-07-17 20:29  TL自动机  阅读(41)  评论(0)    收藏  举报
//鼠标点击特效第二种(小烟花)