题目只要求合法的方案数
我们不难发现,如果当前状态合法,那么右端点右面的所有状态也合法。
先用ST表保证 \(O(1)\) 算出区间最小值,方便判断当前区间是否有合法的咖啡店,再用vector记录每个色调出现的位置,然后一个色调一个色调的计算,若合法则ans加右指针之后所有的点(包括右指针),同时左指针右移;不合法则右指针右移
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<cmath>
#define N 1000010
using namespace std;
int n,k,p,a[N],b[N],f[N][21];
vector<int>c[51];
inline void read(int &x)
{
char c;x=0;int f=1;
while(!isdigit(c))
{
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c))x=x*10+c-'0',c=getchar();
x*=f;
}
inline void build()
{
for(int i=1;i<=n;++i)f[i][0]=b[i];
for(int i=1;i<=20;++i)
for(int j=1;j<=n;++j)
if(j+(1<<i)-1<=n)
f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
inline int query(int i,int j){
int k=floor(log(j-i+1)/log(2));
int ans=min(f[i][k],f[j-(1<<k)+1][k]);
return ans;
}
int main()
{
read(n),read(k),read(p);
for(int i=1;i<=n;++i)
{
read(a[i]),read(b[i]);
c[a[i]].push_back(i);
}
build();
int l=0,r=1,ans=0;
for(int i=0;i<k;++i)
{
l=0,r=1;
while(r<c[i].size())
{
if(l==r)r++;
if(r>=c[i].size())break;
int minn=query(c[i][l],c[i][r]);
// printf("%d %d %d\n",minn,c[i][l],c[i][r]);
if(minn<=p)
{
ans+=c[i].size()-r;
l++;
}
else r++;
}
}
// for(int i=0;i<c[1].size();++i)printf("%d ",c[1][i]);
// printf("\n");
printf("%d",ans);
return 0;
}