选择客栈
选择客栈
首先先不考虑消费的问题。如果一种颜色有n个客栈,那么方案数最多为n*(n-1)/2种。因为有最低消费p,
所以接下来考虑这些方案是否合法。
如果两个最近同色客栈之间是合法的,那序号小的客栈到同颜色的最后一个客栈都是合法的。
怎样判断两个客栈之间是否合法,可以用差分的思想,如果一个客栈是合适的,差分数组就++;
如果用大客栈减小客栈大于0则合法,或者小客栈本身合法。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=2000010;
int n,k,p,sum[maxn];
long long ans;
int a[55][maxn],num[55];
int main()
{
	scanf("%d%d%d",&n,&k,&p);
	for(int x,y,i=1;i<=n;i++)
	{
		scanf("%d",&x);
		num[x]++;
		a[x][num[x]]=i;
		scanf("%d",&y);
		if(y<=p) sum[i]=sum[i-1]+1;
		else sum[i]=sum[i-1];
	}
	for(int x,y,y1,l=0;l<k;l++)
	{
		ans+=num[l]*(num[l]-1)/2;
		for(int i=1;i<=num[l];i++)
		{
		    x=a[l][i];
			for(int j=i+1;j<=num[l];j++)
		    {   
		  	      y=a[l][j];
		 	      if(sum[y]-sum[x]>0||sum[x]-sum[x-1]>0) break;
		 	      else ans--;
		    }
	    }
	}
	cout<<ans;
	return 0;
}

但是这个做法过主要靠数据太水。
O(n)算法:
考虑如果暴力来作这个题,首先是枚举第一个客栈,再枚举第二个客栈,最后枚举是否存在一个客栈满足题意。这是O(n^3)的暴力,如何简化这个暴力.
我们枚举每一个客栈时 如果这个客栈<=p,那么答案就加上在他之前和他同颜色的数量;那如果这个客栈>p,答案肯定是加上在他之前最近的合法的客栈之前的相同颜色的客栈,而这些我们可以预处理里出来。

#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=200100;
int n,k,p,ans=0,now;
int last[maxn];sum[maxn];cnt[maxn],
int main()
{
	scanf("%d%d%d",&n,&k,&p);
    for (int x,y,i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
        if(y<=p) now=i;
        if(now>=last[x]) sum[x]=cnt[x];
        last[x]=i;ans+=sum[x];cnt[x]++;
    }
    cout<<ans;
    return 0;
}

相关文章: