洛谷 P6465 [传智杯 #2 决赛] 课程安排
题意
给定一个数组 \(a\) , 长度 \(l\) , 求连续的子序列个数使得子序列中没有相邻相同的元素 , 且子序列长度大于 \(l\)
特别的 , 首尾元素被认为是相邻的
思路
求连续的子序列考虑双指针 , 序列需要满足两个条件:
-
无相邻元素
-
长度大于 \(l\)
求子序列数目就是求 \(i\) , \(j\) , 使得 \(a_i\) 到 \(a_j\) 满足某种条件
而通常这种双重枚举的 \(O(n^2)\) 的优化方向就是枚举各个点所能贡献出的答案
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long int
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
int n,m;
const int N = 5e5+10;
int a[N];
int cnt[N];
signed main() {
int t = read();
while (t--)
{
memset(cnt,0,sizeof cnt);
n =read();
m =read();
int ans = 0;
for (int i= 1; i<= n; i++)a[i] =read();
int j = 0;
for (int i =1; i< n; i++) {
for (;j<n && (a[j]!=a[j+1]||j<i);) {
++j;
if (j>=i+m-1) {
cnt[a[j]]++;
}
}
ans+= max(0ll,j-(i+m-1)+1-cnt[a[i]]);
if (j>=i+m-1)
cnt[a[i+m-1]]--;
}
cout<<ans<<"\n";
}
return 0;
}