• HDU 5289 Assignment(2015多校训练)


    题目链接:戳我

    题目大意:

    公司有 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;
    }
  • 相关阅读:
    iview表单验证 只能输入小数或者整数
    iView之Modal(一级弹窗和二级弹窗)
    Vue+iView 引入iconfont
    iView爬坑记——表单验证
    有关使用 iview 表单验证的问题
    数据结构
    数学
    Zookeeper
    maven 打包
    区块链
  • 原文地址:https://www.cnblogs.com/tenlee/p/4665464.html
Copyright © 2020-2023  润新知