题目链接:戳我
题目大意:
公司有 n 个员工,编号为1....n,每个员工有能力 a[i],现将这些员工分为若干组,每组的员工的编号必须相连,且满足每组员工任意两个人能力的差值小于 k,可以一个人一组
问能分成多少组。
样例解释:
2 //两组测试样例
4 2 // 分别代表n, k
3 1 2 4 // 代表每个员工的能力,故可分组为[1,1]、[2,2]、[3,3]、[4,4] 、[2,3], 其中为数组的下标,其他均不符合题意,因为相差的值 >= 2
10 5 // 同上
0 3 4 5 2 1 6 7 8 9 // 同上
输出:
5
28
解题思路:
一道简单题。因为数据太大,输出的答案 变量 为 long long 型,而中间的变量没有用long long 型,导致中间变量计算溢出,从而导致答案错误,WA了好多次。
官方题解是这样说的:
解法一:枚举左端点,二分右短点,用st算法求区间最值
解法二:用单调队列维护最值。
本人解法:
维护一个区间的最大和最小值,,同时记录下最大值和最小值 的下标x、 y,当这个区间的最大和最小值 的 差 不满足 k 值时就跳出,得到这个区间的个数len,则有(len-1)*len/2种连续的组合,还要减去与上次重复的组合数。这时继续循环不是从 i+1开始,而是从min(x, y)+1开始。至于为什么要这么做的原因是显然的。
代码:
本人代码,358ms
//Author LJH
//www.cnblogs.com/tenlee
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#define clc(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+10;
long long a[maxn], n, k;
int main()
{
freopen("1002.in", "r", stdin);
int T, x;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i++)
{
scanf("%lld", &a[i]);
}
long long ans = n;
long long ma = a[0], mi = a[0], x, y;
long long len = 1, i = 0, j;
while(i < n-1)
{
x = y = i; //重新初始化
mi = a[i];//重新初始化
ma = a[i];//重新初始化
len = 1;//重新初始化
for(j = i+1; j < n; j++)
{
if(a[j] > ma)
{
ma = a[j]; y = j;
}
if(a[j] < mi)
{
mi = a[j]; x = j;
}
if(ma - mi < k)
{
len++;
}
else
{
break;
}
}
ans += (len-1) * len / 2;
if(j >= n) break;
i = min(x, y) + 1;//下次循环从这里开始
if(i < j)
{
ans -= (j-i) * (j-i-1) / 2; //因为可能会有重复的序列,故要减去
}
}
printf("%lld\n", ans);
}
return 0;
}
标程代码1201ms
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#define LL __int64
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
const int N = 200007;
int min[N][20];
int max[N][20];
int queryMin(int l,int r){
int k=log2((double)(r-l+1));
return Min(min[l][k],min[r-(1<<k)+1][k]);
}
int queryMax(int l,int r){
int k=log2((double)(r-l+1));
return Max(max[l][k],max[r-(1<<k)+1][k]);
}
int calc(int l,int r){
int k=log2((double)(r-l+1));
int MAX=Max(max[l][k],max[r-(1<<k)+1][k]);
int MIN=Min(min[l][k],min[r-(1<<k)+1][k]);
return MAX-MIN;
}
char filein[]={"9.in"};
char fileot[]={"9.out"};
int main(){
// freopen("data/data1002/1002.in", "r", stdin);
// for(int t=0;t<10;++t){
// filein[0]=t+'0';
// fileot[0]=t+'0';
// freopen(filein,"r",stdin);
// freopen(fileot,"w",stdout);
int T;
int n,k,i,j,p;
LL ans;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i){
scanf("%d",&j);
min[i][0]=max[i][0]=j;
}
for(j=1;(1<<j)<=n;++j)
for(i=1;i+(1<<j)-1<=n;++i){
p=(1<<(j-1));
min[i][j]=Min(min[i][j-1],min[i+p][j-1]);
max[i][j]=Max(max[i][j-1],max[i+p][j-1]);
}
int l,r;
ans=0;
for(i=1;i<=n;++i){
l=i,r=n;
while(l+1<r){
p=(l+r)>>1;
if(calc(i,p)<k){
l=p;
}
else{
r=p;
}
}
if(calc(i,r)<k){
p=r;
ans=ans+(LL)(r-i+1);
}
else{
p=l;
ans=ans+(LL)(l-i+1);
}
}
printf("%I64d\n",ans);
}
// fclose(stdin);
// fclose(stdout);
// }
return 0;
}