首先先不考虑消费的问题。如果一种颜色有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;
}