Codeforces Round #582 (Div. 3)

完成essay后最大的感觉就是轻松,放假一般的酸爽,考试什么的都不管了,来一场cf试试手

A. Chips Moving

思路:聚拢筷子问题,所有筷子可以随意移动偶数步,但奇数步移动需要代价,于是将所有筷子移成两列,最后处理少的那列即可得到最小代价

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n,a=0,b=0,s;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d",&s);
        if(s%2==0)
            a++;
        else
            b++;
    }
    printf("%d\n",min(a,b));
    return 0;
}

B. Bad Prices

思路:判断涨价的天数,直接模拟

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+5;

int a[maxn];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)    scanf("%d",&a[i]);
        int now = a[n-1];
        int sum = 0;
        for(int i=n-2;i>=0;i--)
        {
            if(a[i]>now)
                sum++;
            else
                now = a[i];
        }
        printf("%d\n",sum);
    }
    return 0;
}

C. Book Reading

思路:数学问题,求n以内所有m的倍数的个位数之和。由于n可能很大,而m只有个位数会影响结果,于是当然选择逆向处理,先计算n以内m倍数个数,然后从小到大处理。由于每十个数比循环一次,分别处理循环节和最后未完成的循环即可

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
    int q;
    scanf("%d",&q);
    while(q--)
    {
        ll m,n;
        scanf("%I64d%I64d",&n,&m);
        ll num = n/m;
        m %= 10LL;
        //cout << num << endl;
        ll re = 0LL;
        if(num>=10LL)
        {
            ll sum = 0LL;
            for(ll i=1LL;i<10LL;i++)   sum += (i * m) % 10LL;
            re = num / 10LL * sum;
            num %= 10LL;
            //cout << "*" << endl;
        }
        //cout << num << endl;
        while(num)
        {
            //cout << num << endl;
            re += (num * m) % 10LL;
            //cout << "**" << num << "*"<<m << endl;
            num--;
        }
        printf("%I64d\n",re);
    }
    return 0;
}

D2. Equalizing by Division (hard version)

思路:同样,放掉简单版本,有点追求。

数学题,对于一个数组,每次操作可以使数组中某个元素右移一位,求最少的步骤数使得数组中相同元素数量达到要求。

首先,读题最关键,每次操作只能进行一次元素右移。

至于做法,由于元素右移操作具有不可逆性,当然是选择对所有输入变量模拟元素右移操作。至于统计方式,考虑了一种贪心,由于每次移动,必会使操作数+1,即最终结果一定源自于最少移动步数,于是按步数bfs搜索。事实证明这种贪心是错误的,极端数据就是两团很大的数据相聚时,多一步的移动是值得的。

重新思考复杂度,一共n=2e5数据,最大a=2e5,对于单个数据操作数量仅为log(a),显然,数据十分稀疏,暴力是完全行得通的。对于暴力后的结果取舍,选择存取每个数据得到的操作数,然后排序取最小即可得到最优结果。

/*#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+10;

typedef struct CC
{
    int a;accumulate
    int b;
}C;

C c[maxn],d[maxn];

bool cmp(const C aa, const C bb)
{
    if(aa.a>bb.a)
        return true;
    else
        return false;
}

int main()
{
    int n,k,temp;
    scanf("%d%d",&n,&k);
    for(int i=0;i<=2e5+2;i++)
    {
        c[i].a=0;
        c[i].b=0;
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&temp);
        c[temp].a++;
    }
    int pos = 0;
    for(int i=2e5+2;i>=1;i--)
    {
        c[i].b += c[i].a;
        c[i/2].b += c[i].b;
        if(c[i].a>0)
        {
            d[pos].a = c[i].a;
            d[pos].b = c[i].b;
            pos++;
        }
    }
    sort(d,d+pos,cmp);
    n = pos;
    for(pos=0;pos<n;pos++)
    {
        cout << pos << "*" << d[pos].a << "*" << d[pos].b << endl;
        if(d[pos].a>=k)
        {
            printf("0\n");
            break;
        }
        else if(d[pos].b>=k)
        {
            printf("%d\n",k-d[pos].a);
            break;
        }
    }
    if(pos==n)
        printf("%d\n",k);
    return 0;
}
看错题目
*/
/*
#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+10;

typedef struct CC
{
    int now;
    int sum;
    int cnt;
}C;

C c[maxn];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<=2e5+2;i++)
    {
        c[i].now=0;
        c[i].sum=0;
        c[i].cnt=0;
    }
    for(int i=0;i<n;i++)
    {
        int temp;
        scanf("%d",&temp);
        c[temp].now++;
        c[temp].sum++;
    }
    int pos = 1;
    bool ok = true;
    for(int i=0;i<=200000;i++)
    {
        if(c[i].sum>=k)
        {
            printf("0\n");
            ok = false;
            break;
        }

    }
    if(ok)
    {
        while(n)
        {
            int re = 2e7+10;
            n -= c[0].now;
            c[0].now = 0;
            for(int i=1;i<=200000;i++)
            {
                c[i/2].sum += c[i].now;
                c[i/2].now += c[i].now;
                c[i/2].cnt += c[i].now * pos;
                c[i].now = 0;
            }
            bool fi = false;
            for(int i=0;i<=200000;i++)
            {
                if(c[i].sum>=k)
                {
                    fi = true;
                    if(c[i].cnt-(c[i].sum-k)*pos<re)
                        re = c[i].cnt-(c[i].sum-k)*pos;
                }
            }
            if(re < 2e7+10)
            {
                printf("%d\n",re);
                break;
            }
            pos++;
        }
    }
    return 0;
}
*/
/*50 2
72548 51391 1788 171949 148789 151619 19225 8774 52484 74830 20086 51129 151145 87650 108005 112019 126739 124087 158096 59027 34500 87415 115058 194160 171792 136832 1114 112592 171746 199013 101484 182930 185656 154861 191455 165701 140450 3475 160191 122350 66759 93252 60972 124615 119327 108068 149786 8698 63546 187913

50 2
72548 51391 1788 171949 148789 151619 19225 8774 52484 74830 20086 51129 151145 87650 108005 112019 126739 124087 158096 59027 34500 87415 115058 194160 171792 136832 1114 112592 171746 199013 101484 182930 185656 154861 191455 165701 140450 3475 160191 122350 66759 93252 60972 124615 119327 108068 149786 8698 63546 187913
*/
/*
有些时候还是别想当然为好,你想到的策略未必是最优策略,还是暴力大法更科学
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+10;

vector <int> num[maxn];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
        int pos = 0;
        int a;
        scanf("%d",&a);
        num[a].push_back(pos);
        while(a)
        {
            pos++;
            a >>= 1;
            num[a].push_back(pos);
        }
    }
    int ans = 1e7;
    for(int i=0;i<=200000;i++)
    {
        int s = num[i].size();
        if(s>=k)
        {
            sort(num[i].begin(),num[i].end());
            int sum = 0;
            for(int j=0;j<k;j++)
            {
                sum += num[i][j];
            }
            ans = min(ans,sum);
        }
    }
    printf("%d\n",ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值