A、小G的sum

对于每个数,最小的约数是1,最大的约数是它本身。那么使用等差数列求合即可。

void solve() {
    n = read();
    ll ans = n + (1 + n) * n / 2;
    print(ans);
}

B、小G的GCD

对于单个,很容易发现可以被整除的数量有个数。并且发现这些数都是等差数列,公差
那么循环遍历全部的即可找到全部的答案。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 1e6 + 7;
ll n, m;
ll p[N];
void solve() {
    n = read(), m = read();
    ll ans = 0;
    rep(i, m, n)
        ans += (m + (i / m) * m) * (i / m) / 2;
    print(ans);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}

C、小G的约数

首先通过题目观察,很容易得到一个的解法,那就是
那么再看,如果暴力的话,求解一次之后,最大的,对着这个量级再次使用线性算法显然是会超时的。我们重新看上面的式子,这不就是整除分块嘛,那就说明我们可以处理,直接套用求解就出答案了。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 1e6 + 7;
ll n, m;
ll p[N];

// 1
// 1 2
// 1 3
// 1 2 4
// 1 5
// 1 2 3 6
// 1 7
// 1 2 4 8

ll G(ll x) { // \sum i*(n/i)   (n/i)使用整除分块sqrt n处理
    ll ans = 0;
    for (ll l = 1, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ans += (l + r) * (r - l + 1) / 2 * (x / l);
    }
    return ans;
}

void solve() {
    n = read();
    ll ans = G(G(n));
    print(ans);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}

D、小G的LY数对

先说最暴力的解题思路吧,我们使用表做为一个计数器对全部的进行统计。
接下来枚举每一个,并且枚举不同的两个二进制位,将其翻转,既0变1,1变0。去看这个翻转之后的数在计数器中是否出现过,以及出现次数,当然这样做的复杂度就是,前提你的表复杂度是并且常数不能过大,使用常数巨大,大部分人用上面的方法都被卡了,当然我在赛后才交的,发现卡常之后还是可以很稳定的通过的。

这里说几个卡常很重要的点吧。

  1. 使用代替实现计数器。
  2. 容器带来的扩容机制,实现常数巨大无比,那么我们就要使用成员函数直接初始预填充整个容器,避免后续的扩容操作。
  3. 变量放在外面,如果塞在循环内部,它每次并不是直接进行赋值操作,而是新开内存在进行赋值操作,也会带来常数。
  4. 优化,快读快写一起上。
  5. 编译优化全开

因为代码较长,想查看请点击这里
后话:这些都是因为自带的表常数太离谱才卡死那么多人,正解做的是直接手写一个表,差不多可以吧时间压缩在,非常快速,这里忍不住吐槽常数太离谱了hhh。
这里也给个手写的代码吧。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 1e6 + 10;
struct HashSet {
    struct node {
        int k, v, nex;
    } buf[N];
    int h[N], tot, mod = 1000009;
    void insert(int x) {
        int pos = x % mod;
        for (int i = h[pos]; i; i = buf[i].nex) {
            if (buf[i].k == x) { buf[i].v++; return; }
        }
        buf[++tot] = { x, 1, h[pos] };
        h[pos] = tot;
    }
    int find(int x) {
        int pos = x % mod;
        for (int i = h[pos]; i; i = buf[i].nex) {
            if (buf[i].k == x) return buf[i].v;
        }
        return 0;
    }
}mp;

int n, m, a[N];
void solve() {
    int n = read(), m = read();
    rep(i, 1, n)    a[i] = read();
    int x;
    rep(i, 1, m) {
        x = read();
        mp.insert(x);
    }
    ll ans = 0;
    rep(i, 1, n) {
        rep(j, 0, 29)
            rep(k, j + 1, 29) {
            x = (a[i] ^ (1 << j) ^ (1 << k));
            ans += mp.find(x);
        }
    }
    print(ans);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}

E、小G的GLS图

很明显发现,如果遍历建图再去找割点这个题目就搞定了,但是数据规模并不允许我们去建图。
那么我们再看题目有边的描述是,那么我们就可以通过质因数去做为中介点,建立一张的图,记得如果某个素因子只有一个点有,不能新建一个这样的节点和连边,因为它没有别的出边,在跑的时候会把这个点当作割点的因为它的孩子是独立的一个素数,根据割点判定条件他就为真了。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 3200 + 7;

vector<int>    prime;
bool vis[N];
int cnt, n, m, p[N * N];

void getprime() { // 欧拉筛法求素数表O(n)
    memset(vis, true, sizeof(vis));
    cnt = 0;
    for (int i = 2; i < N; ++i) {
        if (vis[i]) prime.push_back(i), ++cnt;
        for (int j = 0; j < cnt; ++j) {
            if (i * prime[j] >= N) break;
            vis[i * prime[j]] = false;
            if (i % prime[j] == 0) break;
        }
    }
}

const int M = 1e5 + 7;
int a[M], dfn[M << 1], low[M << 1], tot;
bool boo[M << 1];

vector<int> v[M];
vector<int> edge[M << 1];

void dfs(int u, int fa) {
    dfn[u] = low[u] = ++tot;
    int child = 0;
    for (auto& v : edge[u]) {
        if (v == fa)    continue;
        ++child;
        if (!dfn[v]) {
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u] and (fa != 0 or child >= 2))
                boo[u] = 1;
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
}

void solve() {
    n = read();
    rep(i, 1, n)    a[i] = read();
    getprime();
    map<int, int> mp;
    rep(i, 1, n) {
        int x = a[i];
        for (auto& it : prime) {
            if (it > x)    break;
            if (x % it == 0) {
                ++mp[it];
                v[i].push_back(it);
                while (x % it == 0)    x /= it;
            }
        }
        if (x != 1) ++mp[x], v[i].push_back(x);
    }
    m = n;
    rep(i, 1, n) {
        for (auto& it : v[i]) {
            if (mp[it] == 1)    continue;
            if (!p[it])    p[it] = ++m;
            edge[i].push_back(p[it]);
            edge[p[it]].push_back(i);
        }
    }
    rep(i, 1, n)
        if (!dfn[i])    dfs(i, 0);
    int ans = 0;
    rep(i, 1, n)    ans += boo[i];
    print(ans);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}