码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 6231 K-th Number

时间:2020-09-18 01:16:59      阅读:36      评论:0      收藏:0      [点我收藏+]

标签:void   emc   break   sum   ||   区间   接下来   number   inline   

HDU 6231 K-th Number

题目大意:

给一个序列A,将其所有的大于等于K长度的子区间中,第K大的数取出来,放到B数组中。求B数组中第M大的数。

思路:

将所有的区间都取出来显然不行,时间复杂度爆炸。维护起来更奇怪。

可以考虑二分答案——先二分出这个B数组中第M大的数x,然后判断行不行——是否在原来的序列A中,有>=M个子区间,其>=x的数至少有K个。

我们知道这里是有单调性的——如果x增大,那么>=x的数至少有K个的区间数目就会变少;否则会增大。

接下来的问题是如何求出>=x的数至少有K个的子区间数目。

我们采用两个指针(l,r)的方法。不停地移动右指针,直到>=x的数有K个之后,移动左指针,直到左指针正好到从它原先位置开始的第一个>=x的数的位置上时——我们可以计算这特定K个数的贡献(具体请见代码qwq)

#include<bits/stdc++.h>
#define MAXN 100010
#define ll long long
using namespace std;
int n,T,maxx,cnt,cnt2;
ll sum;
int a[MAXN],prime[MAXN],cur[MAXN],not_prime[MAXN],Prime[MAXN];
inline void pre_solve(){
	not_prime[1]=1;
	for(int i=2;i<=100000;i++){
		if(not_prime[i]==0){
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=100000;j++){
			not_prime[prime[j]*i]=1;
			if(i%prime[j]==0) break;
		}
	}
}
inline int ll calc(ll x){
    ll cur_ans=0;
    memcpy(cur,a,sizeof(int)*(n+1));
    for(int i=1;i<=n;i++) cur[i]%=x;
    sort(&cur[1],&cur[n+1]);
    int l=1,r=n;
    while(l<r){
        while(cur[l]%x==0) l++;
        while(cur[r]%x==0) r--;
        int cur_sum=cur[l]%x;
        cur_ans+=cur_sum;
        while((cur[r]+cur_sum)>x){
            cur_sum-=x-cur[r];
            r--;
        }
        cur[r]+=cur_sum;
        l++;
    }
    return cur_ans;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    pre_solve();
    while(T--){
        sum=0,maxx=0,cnt2=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
            maxx=max(maxx,a[i]);
        }
        long long ans=sum-maxx;
        int pre=2;
        for(int i=pre;i<=(int)sqrt(sum);i++){
            if(not_prime[i]==true||sum%i!=0) continue;
            else{
                Prime[++cnt2]=i;
                pre=i;
                while(sum%i==0) sum/=i;
            }
        }
        // for(int i=1;i<=cnt2;i++) printf("%d ",Prime[i]); puts("");
        for(int i=1;i<=cnt2;i++){
            ans=min(ans,calc(Prime[i]));
        }
        if(sum!=1) ans=min(ans,calc(sum));
        printf("%lld\n",ans);
    }
    return 0;
}

HDU 6231 K-th Number

标签:void   emc   break   sum   ||   区间   接下来   number   inline   

原文地址:https://www.cnblogs.com/fengxunling/p/13667892.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!