• 省选测试4


    省选测试 4

    T1

    ​ 给你一个 (n) 维的多面体,定义它的面是一个 (n-1) 维多面体,已知它必定有 (2n)面。

    ​ 我们把这个 (n) 维体的所有面都染色。

    ​ 现在,给你这个多面体每一维的长度,然后可以将这个(n)维体划分成 (displaystyle sum_{i=1}^na_i)个每个边的边长为1的小 (n) 维体。

    ​ 定义一个小 (n) 维体的权值是它有多少个面被染色。

    ​ 输出每个权值的小 (n) 维体的个数,显然可以知道,权值范围在 [0, (2n)] 中,所以只需要把 [0, (2n)] 的所有答案都输出即可。

    ​ 答案对469762049取模. (n <= 100000)

    ​ 多项式.

    (a_i = 1)时, 我们发现原来所有的小(i- 1)椎体都会增加染色面两个面变成(i)锥体.

    (a_i >= 2)时, 我们发现只有两遍的小(i - 1)椎体会增加一个染色面, 中间的那些虽然也增加了两个面但是并没有被染色, 所以染色面数不变.

    ​ 所以上面两种情况分别对应着多项式 : (x^2, 2x+(a_i - 2)).

    ​ 然后用分治NTT就好了. 但是我还不会, 于是我用了分治 + NTT, 时间复杂度还是(O(nlog n))的.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 3e5 + 5, mod = 469762049, g = 3;
    int n;
    int a[N];
    int F[N << 1], rev[N << 1];
    
    int ksm(int x, int y) {
        int res = 1;
        while(y) { if(y & 1) res = 1ll * res * x % mod; x = 1ll * x * x % mod; y >>= 1; }
        return res;
    }
    
    void NTT(int len, int *a, int f) {
        for(int i = 0;i < len; i++) if(rev[i] > i) swap(a[i], a[rev[i]]);
        for(int i = 1;i < len; i <<= 1) {
            int w = ksm(g, (mod - 1) / (i << 1));
            if(f == -1) w = ksm(w, mod - 2);
            for(int j = 0;j < len; j += (i << 1)) {
                int k = 1;
                for(int l = 0;l < i; l++, k = 1ll * k * w % mod) {
                    int x = a[j + l], y = 1ll * k * a[j + l + i] % mod;
                    a[j + l] = (x + y) % mod;
                    a[j + l + i] = (x - y + mod) % mod;
                }
            }
        }
        if(f == -1) {
            int INV = ksm(len, mod - 2);
            for(int i = 0;i < len; i++) a[i] = 1ll * a[i] * INV % mod;
        }
    }
    
    void Divide(int l, int r, int *f, int L) {
        if(l > r) return ;
        if(l == r) {
            if(a[l] == 1) f[2] = 1;
            if(a[l] >= 2) f[0] = (a[l] - 2), f[1] = 2;
            return ;
        }
        int mid = (l + r) >> 1;
        Divide(l, mid, f, (mid - l + 1) * 2 + 1); 
        int g[L << 2];
        memset(g, 0, sizeof(g));
        Divide(mid + 1, r, g, (r - mid) * 2 + 1);
        // cout << l << " " << r << "------------->
    ";
        // for(int i = 0;i <= (mid - l + 1) * 2 + 1; i++) cout << f[i] << " "; cout << "
    ";
        // for(int i = 0;i <= (r - mid) * 2 + 1; i++) cout << g[i] << " "; cout << "
    ";
        int len = 1, t = -1;
        while(len < (L << 1)) len <<= 1, t ++;
        for(int i = 0;i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << t);
        NTT(len, f, 1); NTT(len, g, 1);
        for(int i = 0;i < len; i++) f[i] = 1ll * f[i] * g[i] % mod;
        NTT(len, f, -1);
        for(int i = L;i <= len; i++) f[i] = 0;
    }
    
    int main() {
    
        freopen("poly.in","r",stdin); freopen("poly.out","w",stdout);
    
        n = read();
        for(int i = 1;i <= n; i++) a[i] = read();
        Divide(1, n, F, 2 * n + 1);
        for(int i = 0;i <= 2 * n; i++) printf("%d
    ", F[i]);
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    
    /*
    3
    200 203 15
    */
    

    T2

    ​ 给定(n)个形如(y = kx +b)的方程,有(m)个操作.

    (opt=1 : L, R, x,)(x)带入区间([L,R])的方程求最大值.

    (opt=2 : p, v)(k_p)增加为(v).

    (opt=3 : L, R, v)(b_L...b_R += v).

    (n <= 200000, m <= 2000000).

    ​ 分块 + 李超线段树.

    ​ 之前没有学过李超线段树, 学习了一下, 发现这类维护方程的题都可以用它做, 还是很妙的.

    ​ 先分块, 然后对每个块内的所有方程放到一个李超线段树中去维护. 注意有一个细节 : 李超线段树中直接存(k, b)比存最优线段的标号更加方便, 因为更改的时候存标号的话可能会有冲突.

    ​ 对于单点修改(k), 我们相当于得到了一条新的直线, 直接插到李超线段树中就好了, 为什么不用删除呢? 因为原来的那条直线一定不优了.

    ​ 对于区间修改(b), 我们分块改, 对于散块暴力改, 对于整块, 那就相当于把这一块内的所有直线都向上平移了一段, 所以只需要维护一个整块加的标记就好了.

    (O(n sqrt n log n))

    #include <bits/stdc++.h>
    
    #define ls(o) t[o].ls
    #define rs(o) t[o].rs
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f, 1);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 2e5 + 5, M = 550, inf = 1000;
    int n, m, tot, c_;
    int L[N], R[N], rt[N], pos[N];
    long long add_b[N];
    struct Line { long long k, b; } a[N];
    struct point { int ls, rs, Max; long long k, b; } t[N * 50];
    
    inline long long F(long long k, long long b, int i, int x) {
        return 1ll * x * k + b + add_b[pos[i]];
    }
    
    inline double get_inter(long long k, long long b, long long K, long long B) {
        return 1.0 * (B - b) / (k - K);
    }
    
    struct Lichao_tree {
    
        void change(int &o, int l, int r, long long K, long long B, int i) {
            if(!o) {
                o = ++ tot; t[o].k = K; t[o].b = B; t[o].Max = i;
                return ;    
            }
            if(l == r) {
                long long x = F(t[o].k, t[o].b, t[o].Max, l), y = F(K, B, i, l);
                if(y > x) t[o].k = K, t[o].b = B, t[o].Max = i;
                return ;
            }
            long long x = F(t[o].k, t[o].b, t[o].Max, l), y = F(t[o].k, t[o].b, t[o].Max, r), x_ = F(K, B, i, l), y_ = F(K, B, i, r);
            double z = get_inter(t[o].k, t[o].b, K, B);
            if(x_ > x && y_ > y) { t[o].k = K; t[o].b = B; t[o].Max = i; return ; }
            if(x_ <= x && y_ <= y) { return ; }
            if(x_ > x && y_ <= y) {
                if(z <= mid) change(ls(o), l, mid, K, B, i);
                if(z > mid) { change(rs(o), mid + 1, r, t[o].k, t[o].b, t[o].Max); t[o].k = K; t[o].b = B; t[o].Max = i; }
            }
            if(x_ <= x && y_ > y) {
                if(z <= mid) { change(ls(o), l, mid, t[o].k, t[o].b, t[o].Max); t[o].k = K; t[o].b = B; t[o].Max = i; }
                if(z > mid) change(rs(o), mid + 1, r, K, B, i);
            } 
        }
        
        long long query(int o, int l, int r, int k) {
            if(!o) return 0;
            if(l == r) return F(t[o].k, t[o].b, t[o].Max, k);
            long long res = F(t[o].k, t[o].b, t[o].Max, k);
            if(k <= mid) return max(res, query(ls(o), l, mid, k));
            if(k > mid) return max(res, query(rs(o), mid + 1, r, k));
        }
    
    } T[M];
    
    void build() {
        for(register int i = 1;i <= n; i++) T[pos[i]].change(rt[pos[i]], 1, inf, a[i].k, a[i].b, i);
    }
    
    inline long long query(int l, int r, int k) {
        int x = pos[l], y = pos[r];
        // cout << x << " " << y << "---------->
    ";
        long long res = 0;
        if(x == y) {
            for(register int i = l;i <= r; i++) res = max(res, F(a[i].k, a[i].b, i, k)); 
        }
        else {
            // cout << T[x].query(rt[x], 1, inf, k) << "
    ";
            for(register int i = l;i <= R[x]; i++) res = max(res, F(a[i].k, a[i].b, i, k));
            
            for(register int i = x + 1;i <= y - 1; i++) res = max(res, T[i].query(rt[i], 1, inf, k));
    
            for(register int i = L[y];i <= r; i++) res = max(res, F(a[i].k, a[i].b, i, k));
        }
        return res;
    }
    
    inline void change_k(int p, int v) {
        a[p].k += v;
        int x = pos[p];
        T[x].change(rt[x], 1, inf, a[p].k, a[p].b, p);
    }
    
    inline void change_b(int l, int r, int v) {
        int x = pos[l], y = pos[r];
        if(x == y) {
            for(register int i = l;i <= r; i++) {
                a[i].b += v; T[x].change(rt[x], 1, inf, a[i].k, a[i].b, i);
            }
        }
        else {
            for(register int i = l;i <= R[x]; i++) {
                a[i].b += v; T[x].change(rt[x], 1, inf, a[i].k, a[i].b, i);
            }
    
            for(register int i = x + 1;i <= y - 1; i++) add_b[i] += v;
    
            for(register int i = L[y];i <= r; i++) {
                a[i].b += v; T[y].change(rt[y], 1, inf, a[i].k, a[i].b, i);
            }
        }
    }
    
    int main() {
    
        // freopen("data_struct.in","r",stdin); freopen("data_struct.out","w",stdout);
    
        n = read(); m = read(); int B = sqrt(n); c_ = n;
        for(int i = 1;i <= n; i++) a[i].k = read();
        for(int i = 1;i <= n; i++) a[i].b = read();
        for(int i = 1;i <= n; i++) L[i] = 2333333;
        for(int i = 1;i <= n; i++) pos[i] = (i - 1) / B + 1;
        for(int i = 1;i <= n; i++) L[pos[i]] = min(L[pos[i]], i), R[pos[i]] = max(R[pos[i]], i);
        // for(int i = 1;i <= n; i++) cout << F(i, 1) << "
    ";
        build();
        for(int i = 1, opt, l, r, x;i <= m; i++) {
            opt = read();
            if(opt == 1) {
                l = read(); r = read(); x = read();
                printf("%lld
    ", query(l, r, x));
            }
            if(opt == 2) {
                l = read(); x = read();
                change_k(l, x);
            }
            if(opt == 3) {
                l = read(); r = read(); x = read();
                change_b(l, r, x);
            }
        }
    
    
        // fclose(stdin); fclose(stdout);
    
        return 0;
    }
    

    T3

    ​ 到现在题目还没读懂......

    ​ 从上次打完最后的副本之后, 她决心想要出一个有价值的题,然后就有了这道题

    ​ 现在, 她想给小朋友们发糖(大雾),她现在有 n 个薛定谔的糖果盒,她可以进行 m 次如下的三个操作

    1. +1s
    2. 选出 k 个糖果盒,每个糖果盒有 p% 的概率开出糖果。(可以包含已经打开的糖果盒,由于每个糖果盒是量子态的,所以可能之前有糖果的糖果盒这次扣上盒盖的后,可能会变成一个空盒)
    3. 选出来 T 个礼品盒,第 i 个糖果盒有min(P + i - 1,100)% 的概率开出糖果
      现在ta想要知道,她期望最多能拿出多少个糖果。
      结果保留 5 位小数即可

    (P <= 100, T <= 20, N <= 500, M <= 500,Test <= 10)

  • 相关阅读:
    关于win10输入法问题(打不出中文)解决方法
    Docker 修改默认存储位置
    Enabling and Mounting NFS on CoreOS
    docker run mysql
    Specified key was too long; max key length is 767 bytes mysql
    C# 实现 Snowflake算法 ID生成
    无忧之道:Docker中容器的备份、恢复和迁移
    IIS Express 虚拟目录
    从零開始学android&lt;AnalogClock与DigitalClock时钟组件.三十一.&gt;
    jquery版本号升级不兼容的问题:$(&quot;input&quot;).attr(&quot;value&quot;)功能发生改变
  • 原文地址:https://www.cnblogs.com/czhui666/p/14478039.html
Copyright © 2020-2023  润新知