2020牛客暑期多校训练营(第七场)

A Social Distancing


B Mask Allocation

#include 
using namespace std;
const int N = 1e6 + 10;
int res[N], tot;
int n, m, k;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        tot = 0;

        while (n && m) {
            if (n < m) swap(n, m);
            for (int i = 1; i <= m; i++) {
                res[++tot] = m;
            }
            n -= m;
        }

        cout << tot << endl;
        for (int i = 1; i <= tot; i++) {
            cout << res[i] << (i == tot ? "\n" : " ");
        }
    }
    return 0;
}

C. A National Pandemic

2020牛客暑期多校训练营(第七场)_第1张图片

要搞定这道题的几个神仙操作:

F [ x ] = m i n ( F [ x ] , 0 ) F[x]=min(F[x],0) F[x]=min(F[x],0) 相当于开一个数组,每次执行该操作时查询当前 F ( x ) F(x) F(x) 的值,如果大于0,则累加当前值,最后查询时一起减掉
∑ i = 1 c n t w i − d i s ( x i , y ) = ∑ i = 1 c n t ( w i − d e p [ x i ] − d e p [ y ] + 2 d e p [ l c a ( x i , y ) ] ) \sum_{i=1}^{cnt}w_i-dis(x_i,y)=\sum_{i=1}^{cnt}\big(w_i-dep[x_i]-dep[y]+2dep[lca(x_i,y)] \big) i=1cntwidis(xi,y)=i=1cnt(widep[xi]dep[y]+2dep[lca(xi,y)])

后面 dep(lca) 那部分 = 标记根节点到 x i x_i xi的路径上所有出现的点,最后统计 根节点到 y y y 的路径上这些被标记的点出现的次数

啊……学到了学到了……

#include 
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n, m, k;

namespace chain {//树链剖分板子

    vector<int> e[N];

    void add(int u, int v) {
        e[u].push_back(v);
        e[v].push_back(u);
    }

    int dep[N];//深度
    int f[N];//父节点
    int son[N];//重儿子
    int sz[N];//子树大小

    void dfs1(int u, int fa) {
        f[u] = fa;
        dep[u] = dep[fa] + 1;
        sz[u] = 1;

        for (int i = 0, siz = e[u].size(); i < siz; i++) {
            int v = e[u][i];
            if (v != fa) {
                dfs1(v, u);
                sz[u] += sz[v];
                if (sz[v] > sz[son[u]])
                    son[u] = v;
            }
        }
    }

    int dfn = 0, id[N], top[N];

    void dfs2(int u, int tp) {
        id[u] = ++dfn;
        top[u] = tp;
        if (son[u]) dfs2(son[u], tp);
        for (int i = 0, siz = e[u].size(); i < siz; i++) {
            int v = e[u][i];
            if (v != f[u] && v != son[u]) {
                dfs2(v, v);
            }
        }
    }
}
using namespace chain;

struct segTree {
#define ls (o<<1)
#define rs (o<<1|1)

    struct node {
        int l, r;
        int lazy;//往下传的标志 不包括本身
        ll sum;
    } t[N << 2];

    void pushup(int o) {
        t[o].sum = t[ls].sum + t[rs].sum;
    }

    void pushdown(int o) {
        if (t[o].lazy) {
            int len = t[o].r - t[o].l + 1;

            t[ls].lazy += t[o].lazy;
            t[rs].lazy += t[o].lazy;

            t[ls].sum += 1ll * t[o].lazy * (len - (len >> 1));
            t[rs].sum += 1ll * t[o].lazy * (len >> 1);

            t[o].lazy = 0;
        }
    }

    //不带数组 建树
    void build(int o, int l, int r) {
        t[o].l = l;
        t[o].r = r;
        t[o].sum = 0;
        t[o].lazy = 0;
        if (l == r) {
            return;
        }
        int mid = l + r >> 1;
        build(ls, l, mid);
        build(rs, mid + 1, r);
    }
    
    //查询[L,R]区间和
    ll query(int o, int L, int R) {
        if (L <= t[o].l && t[o].r <= R) {
            return t[o].sum;
        }
        pushdown(o);
        int mid = t[o].l + t[o].r >> 1;
        ll res = 0;
        if (L <= mid) res += query(ls, L, R);
        if (R > mid) res += query(rs, L, R);
        pushup(o);
        return res;
    }

    //将[L,R]区间内的点全部+1
    void update(int o, int L, int R) {
        if (L <= t[o].l && t[o].r <= R) {
            t[o].sum += (t[o].r - t[o].l + 1);
            t[o].lazy++; // 出现次数+1
            return;
        }
        pushdown(o);
        int mid = t[o].l + t[o].r >> 1;
        if (L <= mid) update(ls, L, R);
        if (R > mid) update(rs, L, R);
        pushup(o);
    }
} ST;

//更新 u-根节点
void updRange(int u) {
    while (top[u] != 1) {
        ST.update(1, id[top[u]], id[u]);
        u = f[top[u]];
    }
    ST.update(1, 1, id[u]);
}

// u-根节点求和
ll sumRange(int u) {
    ll res = 0;
    while (top[u] != 1) {
        res += ST.query(1, id[top[u]], id[u]);
        u = f[top[u]];
    }
    res += ST.query(1, 1, id[u]);
    return res;
}

ll op_Min[N];

int main() {

    int T, op, w, x, y, cnt;
    ll Sum;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        dfn = 0;
        for (int i = 1; i <= n; i++) {
            op_Min[i] = 0;
            e[i].clear();
            son[i] = 0;
        }

        for (int i = 1; i < n; i++) {
            scanf("%d%d", &x, &y);
            add(x, y);
        }

        dfs1(1, 0);
        dfs2(1, 1);
        ST.build(1, 1, n);

        Sum = 0;// ∑w -∑dep[x]
        cnt = 0;// op1操作次数
        while (m--) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d%d", &x, &w);
                Sum += w - dep[x];
                cnt++;
                // 将x到根节点这一段路径上所有的点都+1
                updRange(x);

            } else if (op == 2) {
                scanf("%d", &x);
                // 当前x点的值
                ll tmp = Sum - 1ll * cnt * dep[x] - op_Min[x] + sumRange(x) * 2;
                if (tmp > 0)
                    op_Min[x] += tmp;

            } else {//op=3
                scanf("%d", &x);
                printf("%lld\n", Sum - 1ll * cnt * dep[x] - op_Min[x] + sumRange(x) * 2);

            }
        }
    }
    return 0;
}

D Fake News

打表发现 ∑ i = 1 n i 2 = x 2   if   n=1   or   n=24 \sum^n_{i=1}i^2=x^2 \texttt{ if n=1 or n=24} i=1ni2=x2 if n=1 or n=24

#include 
using namespace std;
typedef long long ll;

int main() {

    int t;
    scanf("%d", &t);
    while (t--) {
        ll n;
        scanf("%lld", &n);
        
        if (n == 1 || n == 24)
            printf("Fake news!\n");
        else 
            printf("Nobody knows it better than me!\n");
    }
    return 0;
}

E NeoMole Synthesis
F Tokens on the Tree
G Topo Counting


H Dividing

打表找规律

#include 
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
/*
n=15 k=20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0
1 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0
1 1 1 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0
1 1 1 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0
1 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0
纵向 10...1为一组
横向 每组增加一个0

整数分块
*/

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    ll n, k;
    cin >> n >> k;
    ll lim = min(k, n);
    ll res = n % mod, tmp;

    for (ll l = 2, r; l <= lim; l = r + 1) {
        r = n / (n / l);
        if (r > lim) r = lim;

		// 每个完整的一组都有2个1 不完整的一组 只有1个
		// 先将所有组都视为完整的 然后减去不完整的但是被多统计进去的那个1
        res = (res + ((((r - l + 1) * 2) % mod) * (n / l) % mod)) % mod;
        tmp = ((r - l + 1) - ((n % r) ? 0 : 1)) % mod; 
        res = (res + tmp) % mod;
    }

    if (k > n) {
        res = (res + (k - n) % mod) % mod;
    }
    cout << res << endl;
    return 0;
}

I Valuable Forests
J Pointer Analysis

你可能感兴趣的:(多校)