2020ICPC·小米 网络选拔赛第一场

A

枚举倍数就行了

然后挨个去查找, 调和级数nlogn,

这就是好多人这样过的, 这是数据水了....

毕竟 n 是 1e7, 这是卡爆他们的数据

100000
1, 2, ..., 9999, 10000000 

大概需要计算1e8+(还不算循环里的两条指令), 再好的评侧鸡也不能跑到 1e8+ 吧..

所以我们应注意到, 在累加 i 的时候会重复, 枚举素数倍就好了, 复杂度就成了 nloglogn, 2e7+

const int N = 1e7 + 5;
 
int n, m, _, k;
ll a[N], b[N], d[N];
int prime[N], tot;
bool v[N];

void init(int n) {
    rep (i, 2, n) {
        if (!v[i]) prime[++tot] = i;
        for (int j = 1; prime[j] <= n / i && j <= tot; ++j) {
            v[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}

int main() {
    IOS; cin >> n; init(1e7);
    rep (i, 1, n) cin >> a[i], ++b[a[i]];
    ll ans = 0;
    per (i, 1e7, 1) {
        for (int j = 1; prime[j] <= 1e7 / i; ++j) umax(d[i], d[prime[j] * i]);
        umax(ans, d[i] += b[i]);
    }
    cout << ans;
    return 0;
}

B

对每个点能到的点(即 x 到 y 的直线路径上没 墙 )建边, 跑最短路

怎么判线段相交就不贴了, 板子太长, 用你自己的几何板子就行了

int n, m, k, _;
int h[N], ne[M << 1], to[M << 1], tot;
double co[M << 1], dis[N];
bool v[N];

void add(int u, int v, double c) {
    ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
    ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = c; 
}

int main() {
    IOS; cin >> n >> m >> k;
    rep (i, 0, k) pos[i << 1].in(), pos[i << 1 | 1].in();
    rep (i, 0, (k << 1) + 1) {
        dis[i] = 2e9;
        rep (j, i + 1, (k << 1) + 1) {
            bool f = 1;
            rep (_, 0, k - 1) 
                if (pan_cross_LL(pos[i], pos[j], pos[_ << 1], pos[_ << 1 | 1])) f = 0;
            if (f) add(i, j, Len(pos[i] - pos[j]));
        }
    }
    priority_queue<pair<double, int>> q; q.push({ 0, k << 1}); dis[k << 1] = 0;
    while (!q.empty()) {
        int x = q.top().se; q.pop();
        if (v[x]) continue; v[x] = 1;
        for (int i = h[x]; i; i = ne[i]) {
            int y = to[i]; double w = dis[x] + co[i];
            if (w >= dis[y]) continue;
            dis[y] = w; q.push({ -w, y });
        }
    }
    cout << setiosflags(ios::fixed) << setprecision(4) << dis[k << 1 | 1];
    return 0;
}

C

题意模拟,签到题

int main() {
    IOS; string s;
    cin >> s; ll cnt = 0;
    rep (i, 0, s.size() - 1) {
        if (s[i] == 'w') ++cnt;
        if (!i || s[i] == 'v') continue;
        if (s[i] != 'w') continue;
        if (s[i - 1] == 'w') ++cnt;
    }
    cout << cnt;
    return 0;
}

D

tarjan板子题, 板子就不贴, 其他专栏贴过

int main() {
    IOS; cin >> n >> m;
    tot = 1; totc = df = 0;
    rep(i, 1, n) h[i] = dfn[i] = cut[i] = 0;
    rep(i, 1, m) {
        int u, v; cin >> u >> v;
        add(u, v); add(v, u);
    }

    int sum = 0;
    rep(i, 1, n) if (!dfn[i]) root = i, tarjan(i), ++sum;

    rep(i, 1, n) cout << sum + cut[i] << ' ';
    return 0;
}

F

二分就行, 记得 m * L 的地方可能爆ll, 用__int128

ll r[N], l[N], L, R, a[N];
 
bool check(__int128 m) {
    ll cur = 0, res = 0;
    rep(i, 1, n) {
        ll c = a[i] / m;
        if (c < l[i]) return 0;
        umin(c, r[i]); cur += c * m;
        if (c == r[i]) continue;
        res += a[i] % m;
    }
    if (cur + res >= m * L) return 1;
    return 0;
}
 
int main() {
    IOS; cin >> n >> L >> R;
    ll mx = 0, mi = 0, s = 0;
    rep(i, 1, n) cin >> a[i], s += a[i];
    rep(i, 1, n)
        cin >> l[i] >> r[i], mi += l[i], mx += r[i];
    if (mi > R || mx < L) { cout << 0; return 0; }
    ll l = 0, r = s;
    while (l < r) {
        ll mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << l;
    return 0;
}

I

搜索low爆了

你在每个点走的方向唯一的, 那直接将 这个点和将要走到的点合并不好吗?

对环打标记

最后父亲等于自己的 且没有标记的, 是能走出去的点, 答案就是这些点和这些点的孩子的个数

int get(int x, int y) {
    return (x - 1) * m + y;
}
 
int main() {
    IOS; cin >> n >> m;
    rep(i, 1, n) rep(j, 1, m) k = get(i, j), f[k] = k, siz[k] = 1;
    rep(i, 1, n) {
        cin >> s[i] + 1;
        rep(j, 1, m)
            if (s[i][j] == 'S') { if (i + 1 <= n) unit(get(i + 1, j), get(i, j)); }
            else if (s[i][j] == 'W') { if (i - 1 > 0) unit(get(i - 1, j), get(i, j)); }
            else if (s[i][j] == 'A') { if (j - 1 > 0) unit(get(i, j - 1), get(i, j)); }
            else { if (j + 1 <= m) unit(get(i, j + 1), get(i, j)); }
    }
    int ans = 0;
    rep(i, 1, n) rep(j, 1, m) {
        int id = get(i, j);
        if (f[id] != id || v[id]) continue;
        ans += siz[id];
    }
    cout << ans;
    return 0;
}

J

和开关问题一样, 还比他简单, 直接从 (1, 1) 开始改, 当无法改的的时候 不为0 就 QAQ

主要是裸一个二维区间查询和修改的数据结构, 线段树和树状数组都行, 我用的树状(代码短)


int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m >> x >> y;
        rep(i, 1, n) rep(j, 1, m) {
            cin >> a[i][j];
            c[0][i][j] = c[1][i][j] = c[2][i][j] = c[3][i][j] = 0; //树状数组的初始化
        }
        bool f = 1;
        rep(i, 1, n - x + 1) {
            if (!f) break;
            rep(j, 1, m - y + 1) {
                int cur = a[i][j] + ask(i, j, i, j);
                if (cur < 0) { f = 0; break; }
                if (cur == 0) continue;
                add(i, j, i + x - 1, j + y - 1, -cur);
            }
            rep(j, m - y + 2, m) {
                int cur = a[i][j] + ask(i, j, i, j);
                if (cur != 0) { f = 0; break; }
            }
        }
        rep(i, n - x + 2, n) {
            if (!f) break;
            rep(j, 1, m) {
                int cur = a[i][j] + ask(i, j, i, j);
                if (cur != 0) { f = 0; break; }
            }
        }
        if (f) cout << "^_^\n";
        else cout << "QAQ\n";
    }
    return 0;
}
上一篇:小程序·echarts在真机不显示且报错


下一篇:立志·读书