ACM2018年 四川省赛热身赛 C 题 省赛正式赛 B H E 题 题解

热身赛 <C>

题意:

给一个数赋初值1,只能对这个数进行*2, +1, -1, 这三种操作,问他能达到所给数的最小步数。

思路:

DP没得说,但我DP不熟,赛后回味了一下,一直以为是贪心,其实就看当前状态是怎么由上一个状态转移过来的就好了,要预处理一下,代码注释很详细。

本人AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e6 + 5;
int dp[maxn]; //步数
int n;

int main() {
    dp[1] = 0; //1转移到1步数为0
    for(int i = 2; i <= maxn; i++) { //预处理
        if(i & 1) { //奇数时
            int t1 = dp[(i - 1) / 2] + 2; //由它前一个数乘2加1转移过来, 所需2步
            int t2 = dp[(i + 1) / 2] + 2; //由它前一个数乘2减1转移过来, 所需2步
            int tmp = min(t1, t2);
            dp[i] = min(dp[i - 1] + 1, tmp); //由它前一个数加1转移过来, 所需1步, 然后取上述三者最小值
        }
        else { //偶数时
            int t1 = dp[(i - 2) / 2] + 3; //由它前一个数乘2加1再加1转移过来, 所需3步
            int t2 = dp[(i + 2) / 2] + 3; //由它前一个数乘2减1再减1转移过来, 所需3步
            int tmp = min(t1, t2);
            dp[i] = min(dp[i / 2] + 1, tmp); //由它前一个数乘2转移过来, 所需1步, 然后取上述三者最小值
        }
    }
    while(cin >> n && n) {
        cout << dp[n] << endl;
    }

}


正赛:

<H>

题意:给两个数 x, y,求 x + y + Gcd(x, y)

思路:签到题,水的要命。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

int gcd(int x, int y) {
    if(x % y == 0) return y;
    else return gcd(y, x % y);
}

int main() {
    int cas;
    cin >> cas;
    while(cas--) {
        int n, m;
        cin >> n >> m;
        cout << n + m + gcd(n, m) << endl;
    }

}


<B>

题意:

给四个串,输入一个串,看输入的串是给定四个串里哪几个串的不连续子串,区分大小写。

思路:签到题,直接暴力就好了,按照所给用string初始化四个串,然后把输入串的字符按顺序枚举即可。写的有点笨重,没爱多想,就是个水题,觉得没必要太优化写法。当时赛场上那个配置的Vim的strlen( )函数不变色,回来补的时候没问题了,还是自己的Vim用着舒服。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
queue <int> qua;
map <int, int> mp;
int cas;
char s[55];
string s1 = "KanbaraAkihito";
string s2 = "KuriyamaMirai";
string s3 = "NaseHiroomi";
string s4 = "NaseMitsuki";
string ss1 = "Kanbara Akihito";
string ss2 = "Kuriyama Mirai";
string ss3 = "Nase Hiroomi";
string ss4 = "Nase Mitsuki";

int main() {
    cin >> cas;
    while(cas--) {
        int cnt = 0;
        scanf("%s", s);
        int l = strlen(s);

        int c = 0;
        bool f1 = 1, f2 = 1, f3 = 1, f4 = 1;
        int pos = 0;
        for(int i = 0; i < l; i++) {
            for(int j = pos; j < 15; j++) {
                if(s1[j] == s[i]) {
                    c++;
                    pos = j + 1;
                    break;
                }
            }
        }
        if(c >= l) cnt++;
        else f1 = 0;

        c = 0;
        pos = 0;
        for(int i = 0; i < l; i++) {
            for(int j = pos; j < 14; j++) {
                if(s2[j] == s[i]) {
                    c++;
                    pos = j + 1;
                    break;
                }
            }
        }
        if(c >= l) cnt++;
        else f2 = 0;

        c = 0;
        pos = 0;
        for(int i = 0; i < l; i++) {
            for(int j = pos; j < 12; j++) {
                if(s3[j] == s[i]) {
                    c++;
                    pos = j + 1;
                    break;
                }
            }
        }
        if(c >= l) cnt++;
        else f3 = 0;

        c = 0;
        pos = 0;
        for(int i = 0; i < l; i++) {
            for(int j = pos; j < 12; j++) {
                if(s4[j] == s[i]) {
                    c++;
                    pos = j + 1;
                    break;
                }
            }
        }
        if(c >= l) cnt++;
        else f4 = 0;

        cout << cnt << endl;
        if(f1) cout << ss1 << endl;
        if(f2) cout << ss2 << endl;
        if(f3) cout << ss3 << endl;
        if(f4) cout << ss4 << endl;
    }

}


<E>

题意:

日期的表示方法有两种,月/日/年 and 年/月/日,按照格式输入a / b / c,看符合两种表示方式的哪种,如果都符合,就输出这不同两天之间相差多少天;如果只有一种合法或者两种表示方法是同一天,比如 01/02/03 和 02/02/02 ,则按月日年形式输出唯一合法的日期,至少有一种表示方式合法。

思路:

最恶心的签到,给我恶心完了简直,回来补题换了种很系统的写法,先写一个chk函数判断日期合法与否,如下:

bool chk(int y, int m, int d) {
    bool flg = 1;
    if(m > 12 || m == 0) flg = 0;
    if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) {
        if(d == 0 || d > 31) flg = 0;
    }
    else if(m == 4 || m == 6 || m == 9 || m == 11) {
        if(d == 0 || d > 30) flg = 0;
    }
    else if(m == 2) {
        if( (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) ) {
            if(d == 0 || d > 29) flg = 0;
        }
        else {
            if(d == 0 || d > 28) flg = 0;
        }
    }
    return flg;
}

再将输入的两种表示形式都写出来,看有几个合法,如果两个合法,那就分别算他俩与2000/1/1之间的天数,再求差取绝对值即可,如果只有一种满足,那就按题意输出即可,没什么难度,但是非常考验C语言功底,虽然我不是大佬可能没资格说这种话,但是,还是建议初学者认真做一下这题,如果这种恶心题一直扔着不做,以后碰到恶心题就永远做不出来,毕竟身为ACM,AC即一切,如果这题WA到比赛结束,说什么都白扯,话不多说,放下我代码。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
map <int, int> mp;
queue <int> qua;
stack <char> stk;
vector <int> vec;
set <int> st;
int cas;
char s[12];
int a, b, c;
string M[13];

bool chk(int y, int m, int d) {
    bool flg = 1;
    if(m > 12 || m == 0) flg = 0;
    if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) {
        if(d == 0 || d > 31) flg = 0;
    }
    else if(m == 4 || m == 6 || m == 9 || m == 11) {
        if(d == 0 || d > 30) flg = 0;
    }
    else if(m == 2) {
        if( (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) ) {
            if(d == 0 || d > 29) flg = 0;
        }
        else {
            if(d == 0 || d > 28) flg = 0;
        }
    }
    return flg;
}

int main() {
    cin >> cas;
    while(cas--) {
        int D[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        M[1] = "January", M[2] = "February", M[3] = "March", M[4] = "April", M[5] = "May", M[6] = "June";
        M[7] = "July", M[8] = "August", M[9] = "September", M[10] = "October", M[11] = "November", M[12] = "December";

        memset(s, 0, sizeof(s)); //这句必须加,虽然不知道为啥需要清空,但是不清空就会WA
        scanf("%s", s);
        a = s[1] - '0' + 10 * (s[0] - '0');
        b = s[4] - '0' + 10 * (s[3] - '0');
        c = s[7] - '0' + 10 * (s[6] - '0');
        int ya = 2000 + a, ma = b, da = c;
        int yb = 2000 + c, mb = a, db = b;
/* 测一下输出
        cout << ya << "/" << ma << "/" << da << endl; //年月日
        if(chk(ya, ma, da)) cout << "Yes" << endl;
        else cout << "No" << endl;
        cout << yb << "/" << mb << "/" << db << endl; //月日年
        if(chk(yb, mb, db)) cout << "Yes" << endl;
        else cout << "No" << endl;
*/
        if(chk(ya, ma, da) + chk(yb, mb, db) == 2) {
            if(ya == yb && ma == mb && da == db) { //两种都合法看是不是同一天
                cout << M[ma];
                printf(" %d, %d\n", da, ya);
            }
            else {
                int ans = 0, res = 0;

                for(int i = 2000; i <= ya - 1; i++) {
                    if( (i % 4 == 0 && i % 100 != 0) || (i % 400 == 0) ) ans += 366;
                    else ans += 365;
                }
                if( (ya % 4 == 0 && ya % 100 != 0) || (ya % 400 == 0) ) D[2]++;
                for(int i = 1; i <= ma - 1; i++) ans += D[i];
                ans += da;

                D[2] = 28;

                for(int i = 2000; i <= yb - 1; i++) {
                    if( (i % 4 == 0 && i % 100 != 0) || (i % 400 == 0) ) res += 366;
                    else res += 365;
                }
                if( (yb % 4 == 0 && yb % 100 != 0) || (yb % 400 == 0) ) D[2]++;
                for(int i = 1; i <= mb - 1; i++) res += D[i];
                res += db;

                cout << abs(ans - res) << endl;
            }
        }
        else {
            if(chk(ya, ma, da)) {
                cout << M[ma];
                printf(" %d, %d\n", da, ya);
            }
            else if(chk(yb, mb, db)) {
                cout << M[mb];
                printf(" %d, %d\n", db, yb);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/ericgipsy/article/details/80578991
今日推荐