第十二届东北师范大学程序设计竞赛热身赛题解

A. Math loser
首先如果一个 L ( x ) R ( x ) 相同,那么必然不满足条件,所以我们可以排除 x 为素数的情况。
那么我们只需要筛出所有的素数,那么一个数的 L ( x ) R ( x ) 必然是相邻的素数,那么我们就枚举 L R ,来按区间来统计答案惹。
现在考虑一个简单容斥,假如我们要计算的是只能 L R 整除的数的个数,那么我们需要计算出能被 L 整除的数的个数,能被 R 整除的数的个数,然后减去 2 倍的同时能被 L R 整除的数个数即可。
既然能求出个数,那么按等差数列扩展一下就是求和了。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}
int dcmp(double x) {
    return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
    freopen("data_in.txt", "r", stdin);
    freopen("data_out.txt", "w", stdout);
}

namespace Solver {
    const int maxn = 11000000;
    int tag[maxn];
    vector<int> G;
    LL n;
    void shai() {
        for(int i = 2; i < maxn; i++) {
            if(!tag[i]) G.push_back(i);
            for(int j = 0; j < G.size() && i * G[j] < maxn; j++) {
                tag[i*G[j]] = 1;
                if(i % G[j] == 0) break;
            }
        }
    }
    LL cal(LL x, LL v) {
        LL sz = x / v;
        return sz * (sz + 1) / 2 * v;
    }
    LL gao(LL l, LL r, LL v) {
        return cal(r, v) - cal(l-1, v);
    }
    void solve() {
        shai();
        int t;
        scanf("%d", &t);
        while(t--) {
            scanf("%lld", &n);
            LL ans = 0;
            for(int i = 0; i < G.size() - 1; i++) {
                LL ls = 1LL * G[i] * G[i], rs = 1LL * G[i+1] * G[i+1];
                if(ls > n) break;
                rs--;
                rs = min(rs, n);
                ls++;
                ans += gao(ls, rs, G[i]) + gao(ls, rs, G[i+1]) - 2LL * gao(ls, rs, 1LL*G[i]*G[i+1]);
            }
            printf("%lld\n", ans);
        }
    }
};
//1259187438574927161
int main() {
//    file();
    Solver::solve();
    return 0;
}

这里提供一个优雅的暴力,每次跳着素数找,弄出所有的优雅数,因为优雅数的个数很少,所以可过。

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

typedef long long LL;

const int maxn = 3e6+3;
bool vis[maxn];
vector<LL > a;

void init()
{
    memset(vis, false, sizeof vis);
    for(int i=2; i<maxn; i++)
    {
        if(vis[i]) continue;
        a.push_back(i);
        for(int j = 2; i*j<maxn; j++)
            vis[i*j] = true;
    }
    return;
}

int main()
{
    init();
    int T;
    LL n;
    scanf("%d", &T);
    while(T--)
    {
        LL sum = 0;
        scanf("%lld", &n);

        for(int i=0; i<a.size(); i++)
        {
            LL l = a[i]*a[i];
            LL r = min(n+1, a[i+1]*a[i+1]);
            if(l>n) break;

            for(int k=a[i]+1; k*a[i]<r; k++){
                if(k!=a[i+1] && k!=a[i]) {
                    sum += k*a[i];
                }
            }

            for(int k=r/a[i+1]; k*a[i+1]>l; k--){
                if(k!=a[i] && k!=a[i+1]) {
                    sum += k*a[i+1];
                }
            }
        }

        printf("%lld\n", sum);
    }

    return 0;
}

B. A man with iron bone
签到题,模拟题,“我就是退学,倒贴钱,也要坚持打ACM”“嘿嘿。退坑真爽”。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("data_in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
}

namespace Solver {
    using namespace std;
    int t;
    void solve() {

//    file();
        scanf("%d", &t);
        while(t--) {
            string s;
            cin >> s;
            int now = 1;
            for(int i = 0; i < s.size(); i++) {
                if(1 <= now && now <= 3 && s[i] == 'D') now++;
                else if(now >= 4 && now <= 5 && s[i] == 'U') now++;
                else if(now == 6 && s[i] == 'L') now++;
                else if(now == 7 && s[i] == 'U') now++;
                else if(now == 8 && s[i] == 'R') now++;
            }
            if(now == 9) {
                puts("zhen xiang!");
            }
            else {
                puts("wangjingze, e si, siwaibian, tiaoxiaqu!");
            }
        }
    }
};

int main() {
//    file();
    Solver::solve();
    return 0;
}

/*
10
DDDWWLUR
*/

C. Delete substring
这个是我当时看错牛客一个题目的题意得来的
首先删的多肯定可以满足要求,单调性比较显然,因此可以二分。
枚举删掉的子串,可以用前缀和和后缀和快速得到新串的变化次数。
因此二分 + 前缀和后缀和就可以了。
当然也有O(n)的做法。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}
int dcmp(double x) {
    return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
    freopen("data_in.txt", "r", stdin);
    freopen("data_out.txt", "w", stdout);
}

namespace solver {
    int n, m;
    const int maxn = 1100000;
    int pre[maxn], suf[maxn];
    char str[maxn];
    bool check(int x) {
        if(x > n) return 1;
        if(suf[x+1] <= m) return 1;
        for(int i = 2; i <= n - 1; i++) {
            if(i + x - 1 > n) continue;
            int t = i + x - 1;
            if(pre[i-1] + suf[t+1] + (str[i-1] != str[t + 1]) <= m) return 1;
        }
        if(pre[n-x] <= m) return 1;
        return 0;
    }
    void solve() {
        scanf("%d%d%s", &n, &m, str + 1);
        bool isok = 1;
        for(int i = 1; i <= n; i++)
            if(str[i] != 'b')
                isok = 0;
        if(isok) {
            puts("0");
            return ;
        }
        for(int i = 2; i <= n; i++)
            pre[i] = pre[i-1] + (str[i] != str[i-1]);
        if(pre[n] <= m) {
            cout<<n<<endl;
            return ;
        }
        for(int i = n - 1; i >= 1; i--)
            suf[i] = suf[i+1] + (str[i] != str[i+1]);
        int l = 0, r = maxn - 1, m;
        while(l < r) {
            m = l + r >> 1;
            if(check(m)) r = m;
            else l = m + 1;
        }
        cout<<n - l<<endl;
    }
}

int main() {
//    file();
    int t;
    scanf("%d", &t);
    while(t--) solver::solve();
    return 0;
}

D.Guess
签到题,就是想看看大家对题目的理解能力(能不能坑到大家)

#include <iostream>
using namespace std;

int main(){
    puts("a digit in [0, 9], but i don't know which one is correct.");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/meopass/article/details/79940816