水题集合

来源:互联网 发布:淘宝买家秀 编辑:程序博客网 时间:2024/06/13 05:11

codeforces 558C

给N个数字,有两种操作,问最少多少次操作可以使这N个数字大小相同。

operator1 : 把数字乘以2

operator2 : 把数字除以2(int型除法)

cf上的标签是暴力,我不会。看了题解,这种思维我是真的没有,最近打算锻炼思维了,多刷有难度的水题!。

题解:

  开两个数组,vis[maxn*2],cnt[maxn*2],vis[i]表示通过操作可以到达数字i的方式数量。cnt[i]表示所有可以到达数字i的数字到达i所需要的操作数的和。

在输入时,记录最大值。所有数字的最终值不会超过最大值。

然后枚举每个数字,通过位运算算出通过这个数字可以到达的每个状态,并且记录步数。

由于除法要取底。当x&1==1时,再把x向左移直到最大值。这样可以获取到多一些状态。

比如3可以变到8. 3>>1==1; 1<<3 = 8; 需要4步。

处理完以后,扫一遍,看那个数字可以从n个数字出发都达到它。然后去最小值即为答案。

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;int num[100010*2];int vis[100010*2];int cnt[100010*2];int m;void solve(int a){    vis[a] ++;    int s = 0;    int tmp = a;    while(tmp<=m)    {        tmp = tmp<<1;        vis[tmp]++;        s++;        cnt[tmp] += s;    }    tmp = a;    s = 0;    while(tmp)    {        if(tmp&1 && tmp!=1)        {            tmp = tmp>>1;            s++;            vis[tmp] ++;            cnt[tmp] +=s;            int temp = tmp;            int ss = s;            while(temp<=m)            {                temp = temp<<1;                ss++;                vis[temp]++;                cnt[temp]+=ss;            }        }        else        {            tmp = tmp>>1;            s++;            vis[tmp] ++;            cnt[tmp] +=s;        }    }}int main(){    int n;    memset(cnt,0,sizeof(cnt));    memset(vis,0,sizeof(vis));    m = 0;    scanf("%d",&n);    for(int i=0;i<n;i++)    {        scanf("%d",&num[i]);        m = max(m,num[i]);    }    for(int i=0;i<n;i++)    {        solve(num[i]);    }    int res = 0x3f3f3f3f;    for(int i=1;i<=200001;i++)    {        if(vis[i]==n)            res = min(res,cnt[i]);    }    printf("%d\n",res);    return 0;}


原创粉丝点击