题目链接:戳我
题目大意:
公司有 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 ", 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 ",ans); } // fclose(stdin); // fclose(stdout); // } return 0; }