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
", 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
", 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
", _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
", ans * 6);
//        }
    }
    return 0;
}

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

www我还以为这次应该打挺好的。但是写题解的时候发现其实错了很多。

虽然个人感觉比我第一次打省赛要简单,但是其实分数可能还没有第一次省赛好。好难受。估计要没好一点的国奖了。

希望明天出分数的时候能不太难受吧。

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

UPD6.8: 喜提优胜奖

原文地址:https://www.cnblogs.com/Vikyanite/p/14852707.html