Codeforces Round #643 (Div. 2)

31 篇文章 1 订阅
1 篇文章 0 订阅

最近CodeForces比赛有点多,有点刺激,这次A了三题,不过思路太慢了,而且理解题意整的不好

传送门


A题 : 自己没耐心写下去,结果好久好久才过,下次遇到这种题一定记得

解题思路:

  • 主要是暴力,给你一个值就第 k 项的值
    在这里插入图片描述
  • 根据这个式子往后计算就可以,因为每次加的数 1 ~ 81 ,所以百位不是+ 0 就是 + 1,所以最多1000次,他就为将改为变为0,如果存在0,那么他的值肯定就不会变换了,就是这样!

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;


int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll a, k;
        scanf("%lld%lld",&a,&k);
        for (ll i = 1; i <= k -1; i ++){
            ll b = a;
            int mi = 10;
            int mx = 0;
            while(b){
                int t = b % 10;
                mi = min(mi, t);
                mx = max(mx, t);
                b/=10;
            }
            a = a + mi * mx;
            
            if (mi * mx == 0) {
                break;
            }
        }
        printf("%lld\n",a);
    }
    return 0;
}


B题: B题感觉就是自己读题的问题了,对于其中一段话理解有错误,感觉以后还是要多读英文题

解题思路:

  • 题目的大意,一个人的e值,代表这个人可以加入一个组的最少人数(这个组的人数为e或者更多)
  • 因此我们对e从小到大排序,我们只要判断当前队伍人数是否 >= e 值即可,如果是,那么就创建一个队伍出来,最后可以剩人
  • (主要是理解题意)

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 200010;
int a[N];

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
    	int n;
    	scanf("%d",&n);
    	for (int i = 1; i <= n; i++){
    		scanf("%d",&a[i]);
    	}
    	sort(a+1,a+1+n);
    	int res = 0;
    	int num = 0;
    	for (int i = 1; i <= n; i++){
    		res ++;
    		if (res >= a[i]){
    			num ++;
    			res = 0;
    		}
    	}
    	printf("%d\n",num);
    }
}


C题:有很多种解法,这里写一下差分的解法吧(因为比较简单一些),也可以"暴力"

解题思路:

  • 首先我们从A ~ B 模拟第一个数值,那么我们第二个数值的范围是 B ~ C
  • 所以两个数值的和的范围为 A + B ~ B + C
  • 我们枚举第一个位置的值,然后我们将i + B~ i + C 这个范围的值做差分,然后一直枚举完
	for (int i = a; i <= b; i++){
	    ans[i + b] ++;
	    ans[i + c + 1] --;
	}
  • 然后我们进行前缀和处理
    for (int i = 1; i < N ; i++){
        ans[i] += ans[i - 1];
    }
  • 然后思考,我们第三个值是从C + 1开始,那么前面满足的就为ans[i] 个,然后乘第三个值符合的区间数即可
  • 需要注意的是这里的符合区间的值一定是小于C + 1的,因为两边之和大于第三边,然后如果有值超出d,那么前面所有的数值都符合,所有这里注意下范围,可能达到最大的1e6,

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 1000010;

ll ans[N];

int main(){
    int a, b, c, d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    for (int i = a; i <= b; i++){
        ans[i + b] ++;
        ans[i + c + 1] --;
    }
    for (int i = 1; i < N ; i++){
        ans[i] += ans[i - 1];
    }
    ll res = 0;
    for (int i = c + 1; i < N ;i ++){
        ll t = min(i - 1, d) - c + 1;
        res += ans[i] * t; 
    }
    printf("%lld\n",res);
    return 0;
}


D题: 这题有些迷,虽然知道答案,但是不太懂怎么证明的,大体说一下

解题思路:

  • 首先要能取出这个值,就让他前面全为1(就是这样),因为我想让他取不出来。
  • 然后肯定存在n - 1 个 1,然后最后一个值就为 s - (n - 1),所以我们想让有些值不存在我们就让
    n    −    1 > =    s    −    ( n    −    1 )    −    1 n\,\, -\,\,1>=\,\,s\,\,-\,\,\left( n\,\,-\,\,1 \right) \,\,-\,\,1 n1>=s(n1)1
    2 n    >    s 2 n\,\,>\,\,s 2n>s
  • 这种就可以找到,输出no即可
  • 其他的都不可,输出n - 1 个 1,和 s - n + 1即可 (具体证明没太明白)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;


int main(){
    int n, s;
    scanf("%d%d",&n,&s);
    if (s < 2 * n){
        puts("NO");
    }
    else{
        puts("YES");
        for (int i = 1; i <= n - 1; i++){
            printf("%d ",1);
        }
        printf("%d\n",s - n + 1);
        printf("%d\n",n);
    }
    return 0;
}


E题:三分,但是不太会证明他为什么是凹函数

解题思路:

  • 这里是三分高度,最小为0,最大为1e9
  • 然后如果小了的话会花费更多来达到相同的高度,如果大了也会导致相同的情况,所以中间是最好的(但是具体证明还不太明白)
  • 所以我们直接三分就OK,输出他的花费来进行移动
  • 这里注意一下一次 m 就相当于 a + r ,所以我们m = min(m,a + r) 即可

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 100010;

ll h[N];

ll n, a, r, m;

ll check(ll x){
    ll ans = 0; // need to add
    ll res = 0;
    for (int i = 1; i<= n; i ++){
        if (h[i] < x){
            ans += x - h[i];
        }
        else{
            res += h[i] - x;
        }
    }
    ll t = min(ans,res);

    ll num = t * m + (ans - t) * a + (res - t) * r;
    return num;
}

int main(){
    scanf("%lld%lld%lld%lld",&n,&a,&r,&m);

    for (int i = 1; i <= n; i++) scanf("%lld",&h[i]);

    m = min(m, a + r);

    int l = 0, r = 1e9;

    while(l < r){
        int lx = l + (r - l)/3;
        int rx = r - (r - l)/3;
        if (check(lx) < check(rx)){
            r = rx - 1;
        } 
        else{
            l = lx + 1;
        }
    }
    printf("%lld\n",check(l));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值