D2. Equalizing by Division (hard version)
涉及下标运算一定要注意下标是否越界!!!
思路,暴力判断以每个数字为到达态最小花费
#include<bits/stdc++.h> using namespace std; #define sc(x) scanf("%I64d",&x); #define read(A) for(int i=1;i<=n;i++)scanf("%I64d",&A[i]); #define int long long #define P pair<int,int> #define fi first #define se second #define endl ' ' #define ll long long #define maxn 200000+10 int n,m,T; int A[maxn]; int B[200005]; int ch(int x,int y) { for(int i=1;i<=y;i++){ x/=2; } return x; } int Ans=1e18; int check(int x,int t) { int _x=x; if(x==0) { int ans=0; for(int i=B[0]; i<n; i++) { int c=A[i]; while(c) { ans++; c/=2; if(ans>Ans){ return 1e18; } } t++; //cout<<t<<m<<endl; if(t==m) { return ans; } } } int ans=0; int k=2; int y=1; x*=2; while(x<=200000&&t<m) { for(int i=0; i<k; i++) { if(ch(x+i,y)!=_x)break; if(x+i>200000)break; if(x+i<=200000&&B[x+i]>=m-t) { ans+=(m-t)*y; if(ans>Ans)return 1e18; t=m; return ans; } else { ans+=(B[x+i])*y; if(ans>Ans)return 1e18; t+=B[x+i]; } } x*=2; y++; k*=2; } if(m<=t)return ans; else return 1e18; } signed main() { sc(n); sc(m); for(int i=0; i<n; i++) { sc(A[i]); //cout<<A[i]<<endl; B[A[i]]++; if(B[A[i]]>=m) { puts("0"); return 0; } } sort(A,A+n); int t=0; for(int i=0; i<=100000; i++) { t=check(i,B[i]); // if(t<ans)cout<<i<<endl; Ans=min(t,Ans); } cout<<Ans<<' '; }