codeforces 792C. Divide by Three

题目链接:codeforces 792C. Divide by Three

今天队友翻了个大神的代码来问,我又想了遍这题,感觉很好,这代码除了有点长,思路还是清晰易懂,我就加点注释存一下。。。分类吧。删除一个数字模3为M的或删除两个模3为3-M的(还有一些要删零),具体看代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
int L, M, i, j, W, A[100000];
bool C;
string S, R;
int main () {
    cin>>S;
    L=S.length();
    for (i=0;i<L;i++) {
        A[i]=S[i]-‘0‘;
        M=(M+A[i])%3;
    }
    if (M==0) {//不用进行删除
        cout<<S<<‘\n‘;
        return 0;
    }
    for (i=1;i<L;i++) {//从第二个数字开始 选择删除一个数字
        if (A[i]%3==M) {
            for (j=0;j<i;j++) {
                cout<<A[j];
            }
            for (j=i+1;j<L;j++) {
                cout<<A[j];
            }
            cout<<‘\n‘;
            return 0;
        }
    }
    if (A[0]%3==M&&A[1]!=0) {//还是删除一个数字(模3为M),这种情况是第二个数字不为0并且可以删除第一个
        for (j=1;j<L;j++) {
            cout<<A[j];
        }
        cout<<‘\n‘;
        return 0;
    }
    for (i=L-1;i>=0;i--) {//删除两个数字(均是模3为3-M) 或更多
        if (A[i]%3==3-M) {
            if (W) {//判断有两个可删数字
                for (j=0;j<L;j++) {
                    if (j!=W&&j!=i) {//删除两个及以上,可能有前导零
                        if (A[j]) {
                            C=1;
                            cout<<A[j];
                        }
                        else if (C) {
                            cout<<0;
                        }
                    }
                }
                if (!C) {
                    if (L<3) {
                        cout<<-1<<‘\n‘;
                    }
                    else {
                        cout<<0<<‘\n‘;
                    }
                }
                return 0;
            }
            else {
                W=i;
            }
        }
    }
    if (A[0]%3==M) {//删除一个数字或更多 这种情况是第一个数字是模3为M,第二个数字为0。这里先删除第一个数字
        for (j=1;j<L;j++) {
            if (A[j]) {//可能有前导零
                C=1;
                cout<<A[j];
            }
            else if (C) {
                cout<<0;
            }
        }
        if (!C) {
            if (L==1) {
                cout<<-1<<‘\n‘;
            }
            else {
                cout<<0<<‘\n‘;
            }
        }
    }
    return 0;
}
/*//这代码的选择删除 模M 或 模3-M 的顺序很重要, 最后两种方法如果换个先后顺序就错了,比如这组数据//20000111//200001//之前我的做法是同时进行两种删除方法,通过判断哪种方法删除数字更少,来选择输出更优的那个,而这个代码则不用比较两种情况,直接按这种顺序输出就行*/
时间: 2024-07-28 18:43:08

codeforces 792C. Divide by Three的相关文章

CodeForces 792C - Divide by Three [ 分类讨论 ]

删除最少的数位和前缀0,使得剩下的数能被3整除 等价于各数位数字之和能被3整除. 当前数位和可能是 0, 1, 2(mod 3) 0: 直接处理 1: 删除一个a[i]%3 == 1 或者 两个a[i]%3 == 2 2: 同1 对于删完的数列,去掉前置0(只剩前置0就当作0) 若删啥都不满足,则判断原数列中有没有0,不然就输出-1 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int MAXN = 100005; 4 ch

CodeForces - 792C

vj训练时的题,改了两个小时bug.只要把情况都考虑全考虑清楚这个题就比较好写了. 要注意搜索时从后向前搜索比较容易处理10111这种情况. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 char s[100010],s1[100010],s2[100010],s3[100010],s11[100010]; 7 8 int main()

CodeForce-792C Divide by Three(数学)

Divide by Three CodeForces - 792C 有一个正整数 n 写在黑板上.它有不超过 105 位. 你需要通过删除一些位使得他变成一个美丽的数,并且需要删除尽量少的位数.删除的位不一定要连续. 称一个数为美丽的当且仅当这个数不包含前导0并且是 3 的倍数.举个例子,0, 99, 10110 是美丽的数,但 00, 03, 122 不是. 如果没有方案,输出 -1. 如果有多种方案输出任意一种. Input 1033 Output 33 Input 10 Output 0

Educational Codeforces Round 18 C. Divide by Three DP

C. Divide by Three A positive integer number n is written on a blackboard. It consists of not more than 105 digits. You have to transform it into a beautiful number by erasing some of the digits, and you want to erase as few digits as possible. The n

Divide by three, multiply by two CodeForces - 977D (思维排序)

Polycarp likes to play with numbers. He takes some integer number xx, writes it down on the board, and then performs with it n−1n−1 operations of the two kinds: divide the number xx by 33 (xx must be divisible by 33); multiply the number xx by 22. Af

Codeforces Round #479 (Div. 3) D. Divide by three, multiply by two

传送门 D. Divide by three, multiply by two •题意 给你一个数 x,x 可以执行以下两种操作中的一种得到数 y: y 再执行上述两种操作的一种得到数 z: 接着对 z 得到...... 这样依次执行了 n-1 次会得到 n 个数: 现在给你这 n 个数,让你按照上述规则给这 n 个数排序,使得其满足 a1=x , a2=y , a3=z , ........ 输出这 n 个数: •题解 对于任意一个数 x,能通过两种操作得到: ①3x除以3 ②x/2乘2 你会

【博弈论】【SG函数】【找规律】Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) E. Game of Stones

打表找规律即可. 1,1,2,2,2,3,3,3,3,4,4,4,4,4... 注意打表的时候,sg值不只与剩下的石子数有关,也和之前取走的方案有关. //#include<cstdio> //#include<set> //#include<cstring> //using namespace std; //bool vis[16]; //int n,SG[16][1<<16]; //int sg(int x,int moved) //{ // if(SG

【基数排序】Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) C. Jon Snow and his Favourite Number

发现值域很小,而且怎么异或都不会超过1023--然后可以使用类似基数排序的思想,每次扫一遍就行了. 复杂度O(k*1024). #include<cstdio> #include<cstring> using namespace std; int n,k,x,cnts[1110],tmpcnts[1110]; int main() { // freopen("c.in","r",stdin); int X; scanf("%d%d%

Divide by Zero 2018 and Codeforces Round #474 (Div. 1 + Div. 2, combined)G - Bandit Blues

题意:求满足条件的排列,1:从左往右会遇到a个比当前数大的数,(每次遇到更大的数会更换当前数)2.从右往左会遇到b个比当前数大的数. 题解:1-n的排列,n肯定是从左往右和从右往左的最后一个数. 考虑\(S(n,m)\)是1-n排列中从左往右会遇到m个比当前数大的数,考虑把1放在最左边,即\(S(n-1,m-1)\),考虑1不在最左边,有n-1个位置,1不可能会更换\((n-1)*S(n,m)\).即\(S(n,m)=S(n-1,m-1)+(n-1)*S(n-1,m)\) \(S(n,m)\)即