AGC047 简要题解

AGC047 简要题解

A - Integer Product

注意精度问题即可

B - First Second

建颗 trie 树搞一搞即可

C - Product Modulo

考虑用原根解决此问题,乘法变为了加法,因此用桶记录一下 FFT 即可

D - Twin Binary Trees

观察题目性质容易发现树高事 \(\log n\) 的,即使是暴力枚举第一棵树最浅的点复杂度也正确。

因此就暴力枚举,那么一条合法的路径肯定是分别走向两个儿子的,考虑从左儿子走到第二棵树每个节点的贡献,然后再走右儿子找交集即可,注意在更深处有了交集要把父亲的贡献减掉。

E - Product Simulation

好题!用两个简单运算构建起更复杂到操作!

首先你只能有 加 和 比较 两种运算,实现乘法运算。

首先造出 1,\(1 = 0 < (A+B)\) 如果 \(A = B = 0\) 显然数组所有的数都是 0,没有影响的。

计算机是怎样的系统?二进制!所以考虑二进制下的一些运算,有些函数可能与本题无关

And 运算

A & B = 1 < (A + B)

Or 运算

A | B = 0 < (A + B)

Xor 运算

(A < B) + (B < A)

二的整次幂

a[0] = 1;
for (int i = 1;i <= k; i++)
    add(a[0], a[0], 0)

二的整次幂乘 0/1(知道幂的大小)

\(ans = (x>0)<<k\)

二进制拆分

倒着枚举最高位,如果当前数 \(x\)\(2^i\) 大,那么让 \(x -= 2^i\)

减法显然可以移过去变成加法,然后就是一个整次幂乘 0/1 的问题。

乘法操作

先将 A,B 二进制拆分,然后直接乘就行了。

for(int k = 58; k >= 0; k--) {
    answer *= 2;
    for(int i = 0; i <= k; i++){
        int j = k - i;
        if(i < 30 && j < 30) {
            answer += 1<(a_bits[i]+b_bits[j]);
        }
    }
}

这样这道题就已经做完了,我们想想其他的操作。

减法操作

显然我们不可能得出负数,所以实际得出的是 \(\max(0,x-y)\)

\(x-y\) 二进制拆分式的枚举,然后就是二的整次幂乘 0/1

除法操作

还是二进制拆分式的枚举即可

F - Rooks

也是 nb 题

按照题解的说法,我们分三步走

第一步:考虑 \(\Theta(n^2)\) 算法

先按 x 排序,对于一个点来说,显然能走到的区域是一个区间 \([L,R]\),考虑区间 dp,首先枚举位置 t,\(dp[l][r][0/1]\) 表示从位置 t 开始,已经走过区间 \([l,r]\),目前在左右端点的最小代价是多少,转移显然。

容易发现从一个位置有大量的走不到区间,且两个位置有大量的公共区间。考虑倒着 dp,设 \(dp[l][r][0/1]\) 表示从 \([l, r]\) 开始,已经解决了 \([1,l)\cup(r,n]\) 这部分能到的地方的最小代价。这样就是 \(\Theta(n^2)\) 的了。

第二步:考虑横坐标单调且纵坐标单调

从任意一点出发,显然只有两种情况,走到最右边再回来和走到最左边再回来。

第三步:正解

0udoQJ.png
0udfiT.png

从中间那个举行出发,只有这两种情况是合法的,手玩一下可以发现其他的情况都会被挡住,这样就转化为了内部是 \(subtask2\),整体做 \(subtask1\)

看代码会清楚些

const int N = 200500, M = 1000050;
int t[M], x[N], y[N], tx[N], ty[N];
int lt[N], rt[N], n;
void rankit(int *x) {
    memset(t, 0, sizeof(t));
    for (int i = 1;i <= n; i++) t[x[i]]++;
    for (int i = 1;i <= 1000000; i++) t[i] += t[i-1];
    for (int i = 1;i <= n; i++) x[i] = t[x[i]];
}

struct node {
    int x, y, id;
    bool operator < (const node &i) const {
        return x < i.x;
    }
}p[N];

#include <map>
map<pair<int, int> , ll> f[2];
inline int abs(int x) { return x > 0 ? x : -x; }
inline int dis(int a, int b) {
    int dx = abs(x[p[a].id] - x[p[b].id]);
    int dy = abs(y[p[a].id] - y[p[b].id]);
    return dx + dy;
}

const ll inf = 1e18;
ll ans[N];
ll DP(int U, int D, int l, int r, int k) {
    if (f[k].count(MP(l, r))) return f[k][MP(l, r)];
    int L = lt[l-1], R = rt[r+1]; ll ans = inf;
    if (l > 1 && (p[l-1].y == D - 1 || p[l-1].y == U + 1)) {
        ll t = dis(L, k == 0 ? l : r);
        Mn(ans, DP(max(p[L].y, U), min(p[L].y, D), L, r, 0) + t);
    }
    if (r < n && (p[r+1].y == D - 1 || p[r+1].y == U + 1)) {
        ll t = dis(R, k == 0 ? l : r);
        Mn(ans, DP(max(p[R].y, U), min(p[R].y, D), l, R, 1) + t);
    }
    return f[k][MP(l, r)] = (ans == inf ? l - r : ans);
}

int main() {
    read(n);
    for (int i = 1;i <= n; i++) read(x[i]), read(y[i]), tx[i] = x[i], ty[i] = y[i];
    rankit(tx), rankit(ty);
    for (int i = 1;i <= n; i++) p[tx[i]] = (node) {tx[i], ty[i], i};
    sort(p + 1, p + n + 1);
    lt[1] = 1, rt[n] = n;
    for (int i = 2;i <= n; i++)
        lt[i] = abs(p[i].y - p[i-1].y) == 1 ? lt[i-1] : i;
    for (int i = n - 1; i; i--)
        rt[i] = abs(p[i+1].y - p[i].y) == 1 ? rt[i+1] : i;
    for (int i = 1;i <= n; i++)
        ans[p[i].id] = DP(p[i].y, p[i].y, i, i, 0);
    for (int i = 1;i <= n; i++) write(ans[i]);
    return 0;
}

posted @ 2020-09-30 15:53  Hs-black  阅读(409)  评论(1编辑  收藏  举报