Codeforces Round #582 (Div. 3)--D2. Equalizing by Division (hard version)--位运算||BFS

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);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值