题解 P1311 【选择客栈】

题目只要求合法的方案数

我们不难发现,如果当前状态合法,那么右端点右面的所有状态也合法。

先用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;
}
上一篇:noip模拟25


下一篇:2021.07.23 P2474 天平(差分约束)