NOI 模拟赛

T1

给一棵树,每次求链第 $k$ 小,之后把这条链赋值为 $(ans \times x + y)\space mod \space p$

$n \leq 200000$

sol:

树剖,每条重链维护一个珂朵莉树,暴力就完事了

这题不随机复杂度也是对的,因为每次操作完必推平,相当于每次操作最多增加常数个信息量,而珂朵莉树的复杂度是 $O(信息量)$(相同信息会缩到一起),最坏复杂度 $O((n+q)log^2n)$

#include<bits/stdc++.h>
#define LL long long
#define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i)
#define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i)
#define int long long
using namespace std;
inline int read() {
    int x=0,f=1;char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
    for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
    return x*f;
}
const int maxn = 400010;
int n, x, y, p, w[maxn];
int first[maxn], to[maxn << 1], nx[maxn << 1], cnt;
inline void add(int u, int v) {
    to[++cnt] = v;
    nx[cnt] = first[u];
    first[u] = cnt;
}
int size[maxn], fa[maxn], dep[maxn], bl[maxn], pos[maxn], dfn, reg[maxn];
void dfs1(int x) {
    size[x] = 1;
    for(int i=first[x];i;i=nx[i]) {
        if(to[i] == fa[x]) continue;
        fa[to[i]] = x;
        dep[to[i]] = dep[x] + 1;
        dfs1(to[i]);
        size[x] += size[to[i]];
    }
}
void dfs2(int x, int col) {
    bl[x] = col; pos[x] = ++dfn; reg[dfn] = x;
    int k = 0;
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && size[to[i]] > size[k]) k = to[i];
    if(!k) return;
    dfs2(k, col);
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && to[i] != k) dfs2(to[i], to[i]);
}
#define ls (x << 1)
#define rs ((x << 1) | 1)
#define pii pair<int, int>
#define mp make_pair
pii seg[maxn << 2];
int tag[maxn << 2];
inline int isfull(int x, int l, int r) {
    return (seg[x].second == (r - l + 1));
}
void pushup(int x, int l, int r) {
    int mid = (l + r) >> 1;
    if(seg[ls].first != -1 && seg[rs].first != -1 && seg[ls].first == seg[rs].first) {
        seg[x].first = seg[ls].first;
        seg[x].second = (r - l + 1);
    }
    else seg[x].first = -1;
}
void pushdown(int x, int l, int r) {
    if(tag[x]) {
        int mid = (l + r) >> 1;
        seg[ls].first = tag[x]; seg[rs].first = tag[x];tag[ls]=tag[rs]=tag[x]; 
        seg[ls].second = (mid - l + 1), seg[rs].second = r - mid;
        tag[x] = 0;
    }
}
void build(int x, int l, int r) {
    seg[x].first = seg[x].second = -1;
    if(l == r) {
        seg[x] = mp(w[reg[l]], 1);
        return;
    }
    int mid = (l + r) >> 1;
    build(ls, l, mid); build(rs, mid + 1, r);
    pushup(x, l, r);
}
struct seq {
    int l, r, v;
    seq(){}
    seq(int _1, int _2, int _3): l(_1), r(_2), v(_3) {}
    bool operator < (const seq &b) const {
        return v < b.v;
    }
}st[maxn]; int top;
void update(int x, int l, int r, int L, int R, int v) {
    if(L <= l && r <= R) {
        tag[x] = v;
        seg[x].first = v;
        seg[x].second = r - l + 1;
        return;
    }
    pushdown(x, l, r);
    int mid = (l + r) >> 1;
    if(L <= mid) update(ls, l, mid, L, R, v);
    if(R > mid) update(rs, mid + 1, r, L, R, v);
    pushup(x, l, r);
}
void query(int x, int l, int r, int L, int R) {
    if(L <= l && r <= R) {
        if(seg[x].first != -1) {
            st[++top] = seq(l, r, seg[x].first);
            return;
        }
    }
    pushdown(x, l, r);
    int mid = (l + r) >> 1;
    if(L <= mid) query(ls, l, mid, L, R);
    if(R > mid) query(rs, mid+1, r, L, R);
}
int qry(int a, int b, int c) {
    top = 0;
    while(bl[a] != bl[b]) {
        if(dep[bl[a]] < dep[bl[b]]) swap(a, b);
        query(1, 1, n, pos[bl[a]], pos[a]);
        a = fa[bl[a]];
    }
    if(pos[a] > pos[b]) swap(a, b);
    query(1, 1, n, pos[a], pos[b]);
    sort(st + 1, st + top + 1);
    rep(i, 1, top) {
        int len = st[i].r - st[i].l + 1;
        c -= len;
        if(c <= 0) return st[i].v;
    }
}
int upd(int a, int b, int c) {
    while(bl[a] != bl[b]) {
        if(dep[bl[a]] < dep[bl[b]]) swap(a, b);
        update(1, 1, n, pos[bl[a]], pos[a], c);
        a = fa[bl[a]];
    }
    if(pos[a] > pos[b]) swap(a, b);
    update(1, 1, n, pos[a], pos[b], c);
}
signed main() {
    n = read(), x = read(), y = read(), p = read();
    rep(i, 1, n) w[i] = read();
    rep(i, 2, n) {
        int u = read(), v = read();
        add(u, v); add(v, u);
    } dfs1(1); dfs2(1, 1);
    build(1, 1, n);
    int q = read();
    while(q--) {
        int a = read(), b = read(), c = read();
        int res = qry(a, b, c);
        printf("%lld\n", res);
        //cout << "upd: " << (1LL * x * res + y) % p + 1 << endl;
        upd(a, b, (1LL * x * res + y) % p + 1);
    }
}
View Code

有点慌,写的很丑,维护了很多没必要的东西

T2

给 $n$ 个长方体箱子,把它们套在一起,每个箱子里最多有一个箱子(不一定是一层箱子,也就是箱套箱可以放在箱子里),箱子不能旋转,长宽分别小于等于才能套,求最小总占地面积

$n \leq 200$

sol:

首先肯定是算总和 - 最大节省量

1.可以将箱子间的二维偏序关系看成一个有向图,然后最大费用可行流

2.可以将箱子间的嵌套关系看成二分图匹配,求一个二分图最优匹配就完事了

3.可以将每个点拆成出入两个点,每个点限流 $1$,相邻的点连边,$S->入$ ,$出->T$,最大费用可行流

爱咋做咋做,别 dp 就行

#include<bits/stdc++.h>
#define LL long long
#define rep(i,s,t) for(register int i = (s),i##end = (t); i <= i##end; ++i)
#define dwn(i,s,t) for(register int i = (s),i##end = (t); i >= i##end; --i)
using namespace std;
inline int read()
{
    int x=0,f=1;char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
    for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
    return x*f;
}
int n;
struct pos {
    int a,b;
    bool operator < (const pos &y) const {
        if(a == y.a) return b < y.b;
        else return a < y.a;
    }
    bool operator == (const pos &y) const {
        return a == y.a && b == y.b;
    }
}ps[207];
const int maxn = 400010;
struct ZKW {
    #define oo 2147483233
    int n, m, s, t, ans, cost;
    int head[maxn], nx[maxn];
    struct Edge {
        int from, to, caps, cost;
        Edge() {}
        Edge(int _1, int _2, int _3, int _4) : from(_1), to(_2), caps(_3), cost(_4) {}
    } es[maxn];
    void add(int u, int v, int w, int c) {
        es[m] = Edge(u, v, w, c);
        nx[m] = head[u];
        head[u] = m++;
        es[m] = Edge(v, u, 0, -c);
        nx[m] = head[v];
        head[v] = m++;
    }
    ZKW() {
        m = 0;
        ans = 0;
        cost = 0;
        memset(head, -1, sizeof(head));
    }
    queue<int> q;
    int inq[maxn], dis[maxn], vis[maxn];
    int BFS() {
        for (int i = 0; i <= n; i++) dis[i] = -oo;
        dis[t] = 0;
        q.push(t);
        inq[t] = 1;
        while (!q.empty()) {
            int now = q.front();
            q.pop();
            inq[now] = 0;
            for (int i = head[now]; i != -1; i = nx[i]) {
                Edge &e = es[i ^ 1];
                if (dis[e.from] < dis[now] + e.cost && e.caps) {
                    dis[e.from] = dis[now] + e.cost;
                    if (!inq[e.from]) {
                        q.push(e.from);
                        inq[e.from] = 1;
                    }
                }
            }
        }
        if (dis[s] <= 0)return 0;
        cost = dis[s];
        return 1;
    }
    int DFS(int u, int a) {
        if (u == t || !a) {
            ans -= cost * a;
            return a;
        }
        if (vis[u])
            return 0;
        vis[u] = 1;
        int flow = 0, f;
        for (int i = head[u]; i != -1; i = nx[i]) {
            Edge &e = es[i];
            if (dis[e.to] == dis[u] - e.cost && (f = DFS(e.to, min(e.caps, a)))) {
                flow += f;
                a -= f;
                e.caps -= f;
                es[i ^ 1].caps += f;
                if (a == 0)
                    return flow;
            }
        }
        return flow;
    }
    int MCMF(int _s, int _t) {
        s = _s, t = _t;
        int flow = 0, f;
        while (BFS()) {
            do {
                memset(vis, 0, sizeof(vis));
                f = DFS(s, oo);
                flow += f;
            } while (f);
        }
        return flow;
    }
} sol;
int main()
{
    n = read();
    rep(i, 1, n) ps[i].a = read(), ps[i].b = read();
    sort(ps + 1, ps + n + 1);
    n = unique(ps + 1 , ps + n + 1) - ps - 1;
    int S = n + n + 1, T = S + 1; sol.n = T + 2;
    rep(i, 1, n)
    {
        sol.ans+=ps[i].a*ps[i].b;
        rep(j, 1, n)
        if(i!=j&&ps[i].a<=ps[j].a&&ps[i].b<=ps[j].b)
            sol.add(i, j+n, 1, ps[i].a*ps[i].b);
        sol.add(S,i,1,0);
        sol.add(i+n,T,1,0);
        //sol.add(i,T,1,0);
    }sol.MCMF(S, T);
    cout << sol.ans << endl;
}
View Code

T3

求数列 $k$ 次方和

记 $f(x)$ 为 $k$ 次方和的生成函数,$g(x)$ 为从数列中选出 $k$ 个不同的数乘起来的生成函数

则 $f(n) = \sum\limits_{i=1}^{n-1} f(i) \times g(n-i) \times (-1)^{n-i+1} + n \times g(n)$

而 $g(x) = \prod\limits_{i=1}^n (a_i+1)$ 这个生成函数可以分治 + 卷积

$f(x)$ 可以 cdq 分治/多项式求逆

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;/*
const int Size=1<<16;
char buffer[Size],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,Size,stdin);
        tail=(head=buffer)+l;
    }
    if(head==tail) return -1;
    return *head++;
}*/
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int mod = 998244353, maxn = 800010;
int a[maxn], r[maxn], lg[maxn], n, k;
inline int skr(int x, int t) {
    int res = 1;
    while (t) {
        if (t & 1)
            res = 1LL * res * x % mod;
        x = 1LL * x * x % mod;
        t = t >> 1;
    }
    return res;
}
int wn[maxn], iwn[maxn];
void init(int n) {
    wn[0] = iwn[0] = 1; 
    rep(i, 1, n-1) wn[i] = skr(3, (mod - 1) / (i << 1));
    rep(i, 1, n-1) iwn[i] = skr(332748118, (mod - 1) / (i << 1));
}
inline void fft_init(int n) {rep(i, 0, n - 1) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lg[n] - 1));}
inline void fft(int *a, int n, int type) {
    rep(i, 0, n - 1) if (i < r[i]) swap(a[i], a[r[i]]);
    for (int i = 1; i < n; i <<= 1) {
        //int wn = skr(3, (mod - 1) / (i << 1));
        //if (type == -1)
        //    wn = skr(wn, mod - 2);
        int twn = (type == -1) ? iwn[i] : wn[i];
        for (int j = 0; j < n; j += (i << 1)) {
            int w = 1;
            for (int k = 0; k < i; k++, w = 1LL * w * twn % mod) {
                int x = a[j + k], y = 1LL * w * a[j + k + i] % mod;
                a[j + k] = (x + y) % mod;
                a[j + k + i] = (x - y + mod) % mod;
            }
        }
    }
    if (type == -1) {
        int inv_n = skr(n, mod - 2);
        rep(i, 0, n - 1) a[i] = 1LL * a[i] * inv_n % mod;
    }
}
int A[maxn], B[maxn];
int C[maxn], D[maxn];
int mul(int *A, int *B, int len) {
    fft_init(len);
    // fft_init(len);
    fft(A, len, 1);
    // for(int i=0;i<len;i++)cout<<A[i]<<" ";
    // cout<<endl;
    fft(B, len, 1);
    for (int i = 0; i < len; i++) A[i] = (LL)A[i] * B[i] % mod;
    fft(A, len, -1);
    --len;
    while (!A[len]) --len;
    return len;
}
vector<int> poly[maxn];
int solve(int l, int r) {
    if (l == r)
        return poly[l].size() - 1;
    int mid = (l + r) >> 1;
    int ls = solve(l, mid), rs = solve(mid + 1, r);
    int L = 1;
    for (; L <= ls + rs; L <<= 1)
        ;
 
    for (int i = 0; i <= ls; i++) A[i] = poly[l][i];
    for (int i = ls + 1; i < L; i++) A[i] = 0;
 
    for (int i = 0; i <= rs; i++) B[i] = poly[mid + 1][i];
    for (int i = rs + 1; i < L; i++) B[i] = 0;
    poly[l].clear();
    poly[mid + 1].clear();
 
    L = mul(A, B, L);
    for (int i = 0; i <= L; i++) poly[l].push_back(A[i]);
    return L;
}
int g[maxn], f[maxn];
void mulfac(int *A, int *B, int len) {
    fft_init(len);
    fft(A, len, 1);
    fft(B, len, 1);
    for (int i = 0; i < len; i++) A[i] = 1LL * A[i] * B[i] % mod;
    fft(A, len, -1);
}
void cdq_fft(int *f, int *g, int l, int r) {
    if (l == r) {
        (f[l] += (1LL * l * g[l] % mod)) %= mod;
        return;
    }
    int mid = (l + r) >> 1;
    cdq_fft(f, g, l, mid);
    int len = 1, ls = 0, rs = 0;
    // for(;len <= ((r - l + mid)<<1);len <<= 1);
    // for(int i=0;i<len;i++)A[i] = B[i] = 0;
    for (int i = l; i <= mid; i++) C[ls++] = f[i];
    for (int i = 1; i <= r - l; i++) D[rs++] = g[i];
    for (; len <= (ls + rs - 1); len <<= 1)
        ;
    mulfac(C, D, len);
    for (int i = mid + 1; i <= r; i++) f[i] = (f[i] + C[i - l - 1]) % mod;
    for (int i = 0; i < len; i++) C[i] = D[i] = 0;
    cdq_fft(f, g, mid + 1, r);
}
int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    lg[0] = -1; init(1 << 19);
    rep(i, 1, maxn - 1) lg[i] = lg[i >> 1] + 1;
        n = read();
        for (int i = 1; i <= n; i++) {
            a[i] = read();
            if(a[i] >= mod) a[i] -= mod;
            poly[i].push_back(1);
            poly[i].push_back(a[i]);
        }
        solve(1, n);
        for (int i = 0; i < poly[1].size(); i++) g[i] = (((i & 1) ? 1 : (-1)) * poly[1][i] + mod) % mod;
        poly[1].clear();
        cdq_fft(f, g, 0, n);
        for (int i = 1; i <= n; i++) printf("%d\n", f[i]);
}
View Code

这场出了 T2 和 T3

难度非常悬殊的两道题,一道只有一个人没 A,一道只有一个人 A 了

过于真实,引起不适

不出题了QAQ

猜你喜欢

转载自www.cnblogs.com/Kong-Ruo/p/10539714.html