D2. Equalizing by Division (hard version)
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
The only difference between easy and hard versions is the number of elements in the array.
You are given an array aa consisting of nn integers. In one move you can choose any aiai and divide it by 22 rounding down (in other words, in one move you can set ai:=⌊ai2⌋ai:=⌊ai2⌋).
You can perform such an operation any (possibly, zero) number of times with any aiai.
Your task is to calculate the minimum possible number of operations required to obtain at least kk equal numbers in the array.
Don't forget that it is possible to have ai=0ai=0 after some operations, thus the answer always exists.
Input
The first line of the input contains two integers nn and kk (1≤k≤n≤2⋅1051≤k≤n≤2⋅105) — the number of elements in the array and the number of equal numbers required.
The second line of the input contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤2⋅1051≤ai≤2⋅105), where aiai is the ii-th element of aa.
Output
Print one integer — the minimum possible number of operations required to obtain at least kk equal numbers in the array.
Examples
input
Copy
5 3 1 2 2 4 5
output
Copy
1
input
Copy
5 3 1 2 3 4 5
output
Copy
2
input
Copy
5 3 1 2 3 3 3
output
Copy
0
把一个数组内变成至少k个数相同需要的最小步数。
先排序!!然后bfs每个数!当其num值=k之后就不再记录它的步数。不排序wa了n发,原来是因为如果一个大的数遍历到某个数步数肯定要大于某个小点的数到某个数的步数。贪心思想。
位运算一样可以做。
#include <algorithm> //STL通用算法
#include <bitset> //STL位集容器
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque> //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本输入/输出支持
#include<iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <queue> //STL队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL堆栈容器
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string> //字符串类
#include <utility> //STL通用模板类
#include <vector> //STL动态数组容器
#define ll long long
using namespace std;
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
//priority_queue<int,vector<int>,less<int> >q;
int dx[]= {-1,1,0,0,-1,-1,1,1};
int dy[]= {0,0,-1,1,-1,1,1,-1};
const int maxn = 200000+6;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
const int INF=99999999;
int step[maxn];
int num[maxn];
int vis[maxn];
struct node
{
int x;
int step;
};
int k;
queue<node>q;
queue<int>q1;
void bfs(int v)
{
//memset(vis,0,sizeof(vis));
while(q.size())q.pop();
q.push(node{v,0});
vis[v]=1;
while(q.size())
{
int x=q.front().x;
if(num[x]<k)step[x]+=q.front().step;
num[x]++;
//if(x==2)cout<<step[x]<<endl;
if(x!=0&&x/2>=0&&!vis[x/2])
{
//step[x/2]=step[x]+1;
vis[x/2]=1;
q.push(node{x/2,q.front().step+1});
}
q1.push(x);
q.pop();
}
while(q1.size())vis[q1.front()]=0,q1.pop();
}
int a[maxn];
int main()
{
int n;
while(scanf("%d %d",&n,&k)!=EOF)
{
memset(num,0,sizeof(num));
memset(step,0,sizeof(step));
rep(i,1,n)
{
int v;
scanf("%d",&v);
a[i]=v;
}
sort(a+1,a+n+1);
rep(i,1,n)
{
bfs(a[i]);
}
int minn=99999999;
rep(i,0,(int)2e5)
{
if(num[i]>=k)
{
minn=min(minn,step[i]);
}
}
printf("%d\n",minn);
}
}
#include <algorithm> //STL通用算法
#include <bitset> //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex> //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque> //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本输入/输出支持
#include<iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <queue> //STL队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL堆栈容器
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string> //字符串类
#include <utility> //STL通用模板类
#include <vector> //STL动态数组容器
#define ll long long
using namespace std;
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
//priority_queue<int,vector<int>,less<int> >q;
int dx[]= {-1,1,0,0,-1,-1,1,1};
int dy[]= {0,0,-1,1,-1,1,1,-1};
const int maxn = 200000+666;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
const int INF=99999999;
ll step[maxn];
ll num[maxn];
ll k;
void ok(ll x)
{
ll t=x,s=0;
//step[t]+=s;
num[t]++;
while(t>0)
{
//cout<<t<<"---"<<k<<endl;
//cout<<"=="<<endl;
t>>=1;
s++;
if(num[t]<k)
{
//cout<<step[t]<<" --"<<num[t]<<endl;
step[t]+=s;
}
num[t]++;
}
}
ll b[maxn];
int main()
{
int n;
while(scanf("%d %lld",&n,&k)!=EOF)
{
memset(num,0,sizeof(num));
memset(step,0,sizeof(step));
rep(i,1,n)
{
ll v;
scanf("%lld",&v);
b[i]=v;
//ok(v);
}
ll minn=999999999999;
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
{
ok(b[i]);
}
rep(i,0,(int)2e5)
{
if(num[i]>=k)
{
//cout<<step[i]<<" "<<num[i]<<endl;
minn=min(minn,step[i]);
}
}
printf("%lld\n",minn);
}
}