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);
            }
        }
    }
}

發佈了84 篇原創文章 · 獲贊 11 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章