递推,前缀和
题目意思:
注意,题目要求的是,住宿方案的总数。 比如说,连个旅店 x, y,在 区间[x, y] 之间有 10 个 咖啡店满足
消费 <= p, 但只算一种方案。
本题要点:
1、前缀和:
sum[i] 表示前 i个客栈,咖啡消费小于等于p的数量。
2、用vector v[i] 来存颜色是 i 旅店的编号。 后面就可以按颜色分类计算,假设颜色是 i ,
假设现在已经处理完前k个旅店 也就是说 0, 1, …, k - 1 这几个旅店已经计算完,它们之间可以配对的方案数量。
现在加入 a[k], 新增的 配对,只能是 k 和 0 ~ k - 1 这k个旅店之间的配对。
如果区间 [v[i][k], v[i][k - 1]](v[i][k] 表示 v[i] 里 k坐标的旅店编号), 里面有消费 <= p 的旅店,显然新增的 了配对数量就是 k 对。
如果区间 [v[i][k], v[i][k - 1]] 没有有消费 <= p 的旅店, 那么新增的配对,数量就是 k - 1 和 0 ~ k - 2 这 k - 1 个旅店之间的配对数量了。
3、用个变量,累加 每次新增的配对,得到的就是某种颜色的旅店的方案数。 所有颜色累加就是答案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int MaxN = 200010, MaxK = 51;
int color[MaxN], cost[MaxN];
int sum[MaxN]; // sum[i] 表示前 i个客栈,消费小于等于p的数量
int n, k, p;
vector<int> v[MaxK];
void solve()
{
long long ans = 0;
for(int i = 0; i < k; ++i)
{
int s = 0, pre = 0;
int len = v[i].size();
for(int j = 1; j < len; ++j)
{
if(sum[v[i][j]] - sum[v[i][j - 1] - 1] == 0)
{
s += pre;
}else{
s += j;
pre = j;
}
}
// printf("i = %d, len = %d, s = %d\n", i, len, s);
ans += s;
}
printf("%lld\n", ans);
}
int main()
{
int flag = 0;
scanf("%d%d%d", &n, &k, &p);
for(int i = 1; i <= n; ++i)
{
scanf("%d%d", &color[i], &cost[i]);
v[color[i]].push_back(i);
if(cost[i] <= p)
{
flag = 1;
}else{
flag = 0;
}
sum[i] = sum[i - 1] + flag;
}
solve();
return 0;
}
/*
5 2 3
0 5
1 3
0 2
1 4
1 5
*/
/*
3
*/