HDU 6231 K-th Number
阿新 • • 發佈:2020-09-14
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; }