Codeforces Round #452 (Div. 2)

本文提供CodeForces比赛899题目的解析与代码实现,包括团队划分、月份天数验证、数字分割、铲子销售最优解及区间删除问题。通过具体实例介绍了每道题的解题思路和技术要点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:http://codeforces.com/contest/899

899A - Splitting in Teams

题意:给你2*1e5的数,问最多能凑多少个3.(只有1和2)
思路:统计1和2的个数。先算2能匹配多少1.如果2的个数大于等于1的个数,那最大就是2的个数;如果2的个数小于1的个数,那最大的就是cnt2 + (cnt1 - cnt2) /3;

#include<bits/stdc++.h>
using namespace std;
int main ()
{
    //yyy_3y
    //freopen("1.in","r",stdin);
    int n; cin >> n;
    int cnt1 = 0;
    int cnt2= 0;
    for (int i = 1; i <= n; i++) {
       int a; cin >> a;
       if (a == 1) cnt1++;
       else cnt2++;
    }
    int ans = 0;
    if (cnt2 >= cnt1){
        ans = cnt1;
    }
    else {
        ans  = cnt2 + (cnt1 - cnt2) /3;
    }
    cout <<ans <<endl;
}

899B - Months and Years

题意:给你一个小于的24的n,问你是否存以下n个数的连续的月份天数。
思路:赛后和别人交流了下,都选择了存3年,然后中间是闰年,这样就能包含所有的情况。直接暴力搜一遍就行。
我的话是选择记录29的个数,如果29的个数大于1肯定就是NO,然后把29变成28.
存3年搜一次。

#include<bits/stdc++.h>
using namespace std;
int a[100]= {0,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31};
int b[25];
int main ()
{
    //yyy_3y
    //freopen("1.in","r",stdin);
    int n; cin >> n;
    int flag_2 = 0;
    for (int i = 1; i <= n; i++){
        cin >> b[i];
        if (b[i] == 29) flag_2 ++;
        if (b[i] == 29) b[i]--;
    }
    bool flag = 0;
    for (int i = 1; i <= 24; i++){
        int j;
        int ii = i;
        for (j = 1; j <= n; j++){
            if ( a[ii++] != b[j]) break;
        }
        if (j == n + 1) {flag = 1; break;}
    }
    if (flag && flag_2 <= 1) cout << "YES" << endl;
    else cout << "NO" << endl;
}

899C - Dividing the numbers

题意:将集合{1,2,…,n}划分成两个集合,使得两个集合的元素之和的绝对差值最小。
思路:因为n才6e4,我做的很暴力,就求个和,(如果数偶数那差值肯定是0,如果是奇数,那肯定是1),求和之后我就从最后一个开始减,剪到小于自身就行。
标解的话应该分四类情况,分析,算一道数学题把。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100000];
int main ()
{
    //yyy_3y
    //freopen("1.in","r",stdin);
    ll t; cin >> t;
    ll ans = (1 + t)*t/2;
    if (ans & 1) cout << 1 <<endl;
    else cout << 0 <<endl;
    if ( t == 2){
        cout << 1 << " " << 1 <<endl;
        return 0;
    }
    ans = ans /2;
    int cnt = 0;
    while (1){
            a[cnt++] = t;
            ans = ans - t;
            t--;
            if (ans <= t){
                if (ans == 0) break;
                a[cnt++] = ans;
                break;
            }
    }
    cout << cnt;
    for (int i = 0; i < cnt; i++){
        cout << " " << a[i] ;
    }
    cout << endl;

}

899D - Shovel Sale

题意:给你一个1e9的n,1–n,你可以使任意两个数字相加,输出使最后连续为9的位数最长的情况数量。
思路:很显然是一道规律题。
1-4 没有 9。
5-49:最后一位为9
500-4999:最后两位为9
…………
也就是说 5,50,500 …………是分界线。

进行构造和枚举。

1.对于一个五位数如 abcde我们考虑最高位,如果 a 5,那么构造 A= x99999(即五个9),否则 A=x9999(四个9)
枚举 x = 0->8 .
分三类情况。
第一种: n A ,对答案的贡献度为 A/2;
第二种: n (A+1)/2 ,对答案的贡献度为0;
剩下的情况 对答案的贡献度为(2*n-A+1)/2

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main ()
{
    int n; cin >> n;
    if (n < 5) cout << n*(n-1)/2 << endl;
    else {
        ll num = 5; int k;
        for (int i = 1;  i <= 10; i++){
            if (num > n){
                k = i;
                break;
            }
            num *= 10;
        }
        ll temp = 0; int cnt = 0;
        for (int i = 1;i <= k -1; i++){
            temp = temp*10 + 9;
            cnt++;
        }
        ll ans = 0;
        for (int i = 0; i <= 8; i++){
            ll A  = temp + pow(10,cnt) * i;
            if (A <= n) ans += A/2;
            else if (n < (A+1)/2) break;
            else ans += (2*n-A+1)/2;
        }
        cout << ans <<endl;
    }
}

899E - Segments Removal

题意:给定长度为N(200000),每次将序列中长度最大部分相等的区间删去(若有多种情况删去最左端的区间),问多少次操作可以将删完。
题解: 数据结构(。・・)ノ。 优先队列维护一下。
学习到了新的姿势,很开心(●ˇ∀ˇ●)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
priority_queue< pair <int,int>  > q1,del;
int pre[maxn], nxt[maxn], num[maxn], col[maxn];
int cnt = 0;
int ans = 0;
int main ()
{

    int n; scanf("%d",&n);
    for (int i = 1; i <= n; i++){
        int x; scanf("%d",&x);
        if (x == col[cnt]) num[cnt]++;
        else col[++cnt] = x, num[cnt] = 1;
    }
    for (int i = 1; i <= cnt; i++){
        pre[i] = i-1;
        nxt[i] = i+1;
        q1.push(make_pair(num[i],-i));
    }
    while (cnt){
         while (!del.empty() && del.top() == q1.top()) q1.pop(), del.pop();
         int tt = -q1.top().second; q1.pop();
         int t1 = pre[tt];
         int t2 = nxt[tt];
         nxt[t1] = t2;
         pre[t2] = t1;
         if (t1 && col[t1] == col[t2]){  //合并
            del.push(make_pair(num[t2],-t2));
            del.push(make_pair(num[t1],-t1));
            num[t1] += num[t2];
            nxt[t1] = nxt[t2];
            pre[nxt[t2]] = t1;
            q1.push(make_pair(num[t1],-t1));
            cnt--;
         }
         cnt--,ans++;
    }
    printf("%d\n",ans);
    return 0;
}
/*
12
22 22 22 1 333 333 333 333 1 22 22 22
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值