2021.6.5 藍橋杯國賽B組


A.帶寬

沒啥好說的8b = 1B,所以直接200 / 8 = 25即可

大家應該都對的吧(除了我可憐的濤醬

B.純質數

純打表題。我的答案:1903

附上打表程序。

#include <bits/stdc++.h>
using namespace std;
int dic[8] = {2,3,5,7};

bool check(int x) {
    while (x) {
        int a = x % 10;
        int flag = 0;
        for (int i = 0; i < 4; i ++) {
            if (a == dic[i]) {
                flag = 1;
            }
        }
        if (flag == 0) return 0;
        x /= 10;
    }
    return 1;
}

int main() {
    int ans = 0;
    for (int i = 2; i <= 20210605; ++ i) {
            int flag = 0;
        for (int j = 2; j *j <= i; ++ j) {
            if (i % j == 0) {
                flag = 1;
                break;
            }
        }
    if (flag == 0 && check(i)) ans ++;
    }
    cout << ans << endl;
    return 0;
}

C.完全日期

簡單模擬。我的答案:983 ------UPD:忘記判二月了,答案為977

附上程序:

#include <bits/stdc++.h>
using namespace std;
int dbound[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int isrun(int year) {
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}

int getsum(int x) {
    int sum = 0;
    while (x) {
        sum += x % 10;
        x /= 10;
    }
    return sum;
}

bool check(int year, int month, int day) {
    int sum = 0;
    sum += getsum(year);
    sum += getsum(month);
    sum += getsum(day);
    int base = sqrt(sum);
    return base * base == sum;
}

int main() {
    int year = 2001, month = 1, day = 1;
    int ans = 0;
    while (1) {
        if (check(year, month, day)) {
            ans ++;
            cout << year << " " << month << " " << day << endl;
        }
        if (year == 2021 && month == 12 && day == 31) {
            break;
        }
        day ++;
        if (day > dbound[month] + isrun(year)) { ///這里忘記判二月了。擺爛
            month ++;
            day = 1;
        }
        if (month > 12) {
            year ++;
            month = 1;
        }
    }
    cout << ans << endl;
    return 0;
}

D. 最小權值

www這道題是個DP賽中看出來了。但是礙於DP水平有限(其實就是沒有),被卡了很久。直到最后也沒寫出來。

怎么身邊的人都秒掉了www真的該好好學學dp了。

(沒做出來之后補)

E.大寫

沒啥好說的。

#include <bits/stdc++.h>
using namespace std;
char s[105];

int main() {
    scanf("%s", s);
    int n = strlen(s);
    for (int i = 0; i < n; ++ i) {
        if (s[i] <= 'z' && s[i] >= 'a')
            s[i] = s[i] - 'a' + 'A';
    }
    cout << s << endl;
    return 0;
}

F.123

這道題較為簡單。首先二分求出所求數字在哪一個塊里。之后通過暴力求出之前的塊的和是多少。之后再前綴和求出當前塊的是多少即可。

UPD:這個想法似乎是錯的。問題就出在暴力跑出之前塊的和是多少這一步。n的范圍是1-1e12開根號之后就是1e6之后T又是1e6那么這個做法會被卡到1e12的復雜度。直接見祖宗。

跟隊友交流了一番他們說是二維前綴和來優化這一步操作。www之后再想想吧

附上代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll get(ll x) {
    ll L = 1, R = 1e6;
    ll ans = 0;
    while (L <= R) {
        ll mid = L + R >> 1;
        if (mid * (mid + 1) / 2 <= x) {
            L = mid + 1;
            ans = max(ans, mid);
        }
        else {
            R = mid - 1;
        }
    }
    ll sum = 0;
    for (int i = 1; i <= ans; ++ i) {
        sum += 1ll * i * (ans - i + 1);
    }
    ll res = x - ans * (ans + 1) / 2;
    sum += res * (res + 1) / 2;
//    cout << ans << " " << sum << endl;
    return sum;
}

int main() {
    int T; scanf("%d", &T);
    while (T--) {
        ll l, r; scanf("%lld%lld", &l, &r);
        printf("%lld\n", get(r) - get(l-1));
    }
    return 0;
}

G.異或變換

當時猜了個結論覺得循環節不是很大所以這做這道題的關鍵就是找循環節。

各種STL代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000+10;
int n;
ll t;
char s[maxn];
bitset<maxn> bt;
unordered_map<bitset<maxn>, int> mp;
vector<bitset<maxn> > rec;

void out(bitset<maxn> b) {
    for (int i = 0; i < n; i++)
        cout << b[i];
    cout << endl;
}
int main() {
    scanf("%d%lld", &n, &t);
    scanf("%s", s);
    for (int i = 0; i < n; ++ i) {
        bt[i] = (s[i] == '1');
    }
//    out(bt);
    rec.push_back(bt);
    mp[bt] = 0;
    ll st = t, len = 1;
    for (int i = 1; i <= t; ++ i) {
        bitset<maxn> temp;
        temp[0] = bt[0];
        for (int j = 1; j < n; ++ j) {
            temp[j] = (bt[j] != bt[j-1]);
        }
        swap(bt, temp);
//        out(bt);
        if (mp.count(bt)) {
            st = mp[bt];
            len = i - st + 1;
            break;
        }
        mp[bt] = i;
        rec.push_back(bt);
    }
//    cout << st << " " << len << endl;
//    cout << st + t % len <<endl;
    out(rec[st + t % len]);
    return 0;
}

H.二進制問題

非常典型的數位dp問題。直接組合數算貢獻也是可以做的。但是很遺憾的是我是數位dp板子型選手。無奈只能敲了暴力。

艹寫題解的時候發現暴力敲錯了。去世了。似乎把算二進制最高位算成十進制最高位了。直接升天。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000+10;
ll n;
int k;
ll pw2[65];
int lmt = 0;
ll ans = 0;
void DFS(ll sum, int cnt, int wei) {
//    cout << sum << " " << cnt << " " << wei << endl;
    if (sum > n) return ;
    if (cnt > k) return ;
    if (wei > lmt) {
        if (cnt == k) {
//            cout << sum << endl;
            ans ++;
        }
        return ;
    }

    DFS(sum + pw2[wei], cnt + 1, wei + 1);
    DFS(sum, cnt, wei + 1);
}

int main() {
    scanf("%lld%d", &n, &k);
    pw2[0] = 1;
    for (int i = 1; i <= 62; ++ i) {
        pw2[i] = pw2[i-1] * 2;
//        cout << pw2[i] << endl;
    }
    ll tn = n;
    while (tn) {
        tn /= 2; ///這里寫成了10
        lmt ++;
    }
    lmt ++;
    DFS(0, 0, 0);
    printf("%lld\n", ans);
   // cout << lmt << endl;;
    return 0;
}

I.翻轉括號序列

寫了份暴力。復雜度是n * m。用bitset優化了翻轉過程

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000000+10;
int n, m;

bitset<maxn> bt;
char s[maxn];
int _find(int st) {
    int flag = 0;
    int ans = 0;
    for (int i = st; i <= n; ++ i) {
        if (bt[i] == 1) {
            flag ++;
        }
        else {
            flag --;
            if (flag < 0) {
                return ans ;
            }
            if (flag == 0) ans = i;
        }
    }
    return ans;
}
vector<bitset<maxn> > Lbt;
vector<bitset<maxn> > Rbt;
/*
7 5
((())()
 */

void out(bitset<maxn> b) {
    for (int i = 1; i <= n; ++ i)
        cout << b[i];
    cout << endl;
}

int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", s+1);
    bitset<maxn> b2, b1;
    for (int i = 1; i <= n; ++ i) {
        b2[i] = 1;
    }
    Lbt.push_back(b1);
    Rbt.push_back(b2);

    for (int i = 1; i <= n; ++ i) {
        bt[i] = (s[i] == '(');
        b1[i] = 1;
        Lbt.push_back(b1);
        Rbt.push_back(b1^b2);
    }
    for (int i = 1; i <= m; ++ i) {
        int oper;
        scanf("%d", &oper);
//        out(bt);
        if (oper == 1) {
            int l, r; scanf("%d%d", &l, &r);
            bt = bt ^ Rbt[0] ^ Lbt[l-1] ^ Rbt[r];
//            out(Rbt[0]);
//            out(Lbt[l-1]);
//            out(Rbt[r]);
//            out(bt);
        }
        else {
            int l; scanf("%d", &l);
            printf("%d\n", _find(l));
        }
    }
    return 0;
}

J.異或三角形

看了下應該是算貢獻一類的題目。但是沒啥時間就寫了發n2的暴力

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000+10;

bool check(int x, int y, int k) {
    if (x + y > k && x + k > y && y + k > x) return 1;
    return 0;
}

int main() {
    int T; scanf("%d", &T);
    while (T--) {
        int n; scanf("%d", &n);
        int ans = 0;
//        for (int n = 1; n <= 100; ++ n) {
            for (int i = 1; i <= n; ++ i) {
                    for (int j = i+1; j <= n; ++ j) {
                        int k = i ^ j;
                        if (k > j && check(i, j, k)) {
                            ans ++;
//                                cout << i << " " << j << " " << k << endl;
                        }
                    }

            }
//            cout << ans << endl;
            printf("%d\n", ans * 6);
//        }
    }
    return 0;
}

 

--------------------------------------------------

www我還以為這次應該打挺好的。但是寫題解的時候發現其實錯了很多。

雖然個人感覺比我第一次打省賽要簡單,但是其實分數可能還沒有第一次省賽好。好難受。估計要沒好一點的國獎了。

希望明天出分數的時候能不太難受吧。

-------------------------------------------------------

UPD6.8: 喜提優勝獎

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM