zoukankan      html  css  js  c++  java
  • [BJOI2019]总结

    排兵布阵

      (过水已隐藏)

    光线

      算法:数学、物理。

      忽略(\%)为了行文方便。一种直接的方法:构建图以及概率的转移。定义光线方向朝下,且在第(i)个玻璃和(i+1)个玻璃之间((i=0)表示第一块玻璃的上方,(i=n)表示在最后一块玻璃的下方)的光线总数为(f_i)。那么我们想要的答案即为(f_n)。然后我们列出来转移,发现有

    [f_i=f_{i-1} imes a_{i-1}+sum_{ileqslant j<n}f_j imes dis_{i o j} ]

      其中边界

    [f_0=1 ]

      其中(dis_{i o j})表示光线在(i)(i+1)块玻璃间且朝下反射后朝上到达了(j)(j+1)玻璃之间后又回到了第(i)(i+1)块玻璃之间,不难列出来

    [dis_{i o j}=b_{i+1}b_jprod_{j<kleqslant i}a_k ]

      这样不重不漏地分成了从上往下从下返回到上回到(j)的两种情况。直接高消可以通过(50pts)(nleqslant 100)。不难发现变量只与后缀的(f)有关,相当于消元矩阵已经变成上三角的了,我们可以采用回代的方式解出来(f_n)。具体的就是把上式先变形:

    [f_{i-1}=frac{f_i-sum_{ileqslant j<n}f_j imes dis_{i o j}}{a_{i-1}} ]

      题目保证(a_i e0)。这个(sum_{ileqslant j<n}f_j imes dis_{i o j})是可(mathcal O(1))转移的。然后用(f_i)表示(f_{i-1}),最后我们可以得到(f_0)(f_n)的关系式。求个逆元即可。复杂度(mathcal O(n))

    #include <bits/stdc++.h>
    
    #define rep(i, a, b) for (int i = a, i##end = b; i <= i##end; ++i)
    #define per(i, a, b) for (int i = a, i##end = b; i >= i##end; --i)
    #define rep0(i, a) for (int i = 0, i##end = a; i < i##end; ++i)
    #define per0(i, a) for (int i = a-1; ~i; --i)
    #define chkmax(a, b) a = std::max(a, b)
    #define chkmin(a, b) a = std::min(a, b)
    
    const int maxn = 555555;
    const int P = 1e9 + 7;
    
    int n, a[maxn], b[maxn], inva[maxn], f[maxn];
    
    int qpow(int a, int b) {
        int res = 1;
        for (int i = a; b; i = 1ll*i*i%P, b >>= 1)
            if (b & 1) res = 1ll*res*i%P;
        return res;
    }
    
    #define inv(x) qpow(x, P-2)
    const int inv100 = inv(100);
    
    int main() {
        n = read();
        rep(i, 1, n) a[i] = 1ll*read()*inv100%P, b[i] = 1ll*read()*inv100%P, inva[i] = inv(a[i]);
        f[n] = 1;
        int suf = 0;
        per(i, n, 1) {
            f[i-1] = 1ll*(f[i]-1ll*suf*b[i]%P+P)*inva[i]%P;
            suf = (1ll*suf*a[i] + 1ll*f[i-1]*b[i])%P;
        }
        printf("%d", inv(f[0]));
        return 0;
    }
    

      其中suf维护(sum_{ileqslant j<n}f_i imes b_{i+1}prod_{j<kleqslant i}a_k),表示与(f_n)的关系,不顺道维护(b_j)原因在于转移时可能会遇到(b_j=0)的情况导致除不了(我第一把30pts的理由)。

      还有一种极妙的方法:既然是一道物理题,我们通过物理中等效替代法,将两块玻璃合并成一块玻璃。不难看出总透过率为在两块玻璃之间往复0次、1次、...相当于一个无穷级数求和,同理反射率也为如此,最后可以得到

    [a_{总}=a_1a_2sum_{i=0}^infty(b_2b_1)^i=frac{a_1a_2}{1-b_1b_2} ]

    [b_{总}=b_1+a_1^2sum_{i=1}^infty b_1^{i-1}b_2^i=b_1+frac{a_1^2b_2}{1-b_1b_2} ]

      合并到只剩一块玻璃即可。

    删数

      算法:线段树(维护区间0的个数

      先统计(a_i=k)的数的个数,记作(b_i)。对于所有的(b_i),我们将([i-b_i+1,b_i])全部打上标记,最终([1,n])没有打上标记的位置就是答案。证明显然,消除完的充要条件([1,n])内全部打上标记,然后每次你只能移一个重复覆盖的数去填一个没标记的位置。特殊的就是对于(a_i>n)的情况,这个不能参与打标记的部分(它不可能参与删除)

      然后就是拿一颗线段树来维护这样的东西,由于有修改操作,我们不能维护0/1,而要维护区间加和区间查询0的个数。这里通过维护区间最小值以及最小值的个数(因为区间最小值只能为0,可用该方法),然后进而维护。对于(i>n)的情况,只有数组整体修改时会出现,此时把它在线段树上去掉即可,反之亦然。

      稍微麻烦的就是操作二,此时记一个offset表示整体偏移,然后其它的依此调整。

      复杂度(mathcal O(nlog n))一定要注意空间大小、位置的计算!

    #include <bits/stdc++.h>
    
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define rep(i, a, b) for (int i = a, i##end = b; i <= i##end; ++i)
    #define per(i, a, b) for (int i = a, i##end = b; i >= i##end; --i)
    #define rep0(i, a) for (int i = 0, i##end = a; i < i##end; ++i)
    #define per0(i, a) for (int i = a-1; ~i; --i)
    #define chkmax(a, b) a = max(a, b)
    #define chkmin(a, b) a = min(a, b)
    
    const int maxn = 155555;
    
    #define ls (o << 1)
    #define rs (o << 1 | 1)
    
    int buf[maxn << 2];
    int n, m, a[maxn], *b, offset = 0;
    
    int minv[maxn << 4], cnt[maxn << 4], val[maxn << 4], tag[maxn << 4];
    
    void build(int o, int l, int r) {
        minv[o] = tag[o] = 0, cnt[o] = val[o] = r-l+1;
        if (l == r) return;
        int mid = l+r>>1;
        build(ls, l, mid), build(rs, mid+1, r);
    }
    
    void pushup(int o) {
        val[o] = val[ls] + val[rs];
        minv[o] = min(minv[ls], minv[rs]);
        cnt[o] = (minv[o] == minv[ls] ? cnt[ls] : 0) + (minv[o] == minv[rs] ? cnt[rs] : 0);
    }
    
    void pushdown(int o) {
        if (!tag[o]) return;
        tag[ls] += tag[o], tag[rs] += tag[o]; minv[ls] += tag[o], minv[rs] += tag[o];
        val[ls] = minv[ls] ? 0 : cnt[ls]; val[rs] = minv[rs] ? 0 : cnt[rs];
        tag[o] = 0;
    }
    
    void modify(int o, int l, int r, int ql, int qr, int v) {
        if (ql <= l && r <= qr) {
            tag[o] += v; val[o] = (minv[o] += v) ? 0 : cnt[o];
            return;
        }
        pushdown(o);
        int mid = l+r>>1;
        if (ql <= mid) modify(ls, l, mid ,ql, qr, v);
        if (mid < qr) modify(rs, mid+1, r, ql, qr, v);
        pushup(o);
    }
    
    int query(int o, int l, int r, int ql, int qr) {
        if (ql <= l && r <= qr) return val[o];
        pushdown(o);
        int mid = l+r>>1, res = 0;
        if (ql <= mid) res += query(ls, l, mid ,ql, qr);
        if (mid < qr) res += query(rs, mid+1, r, ql, qr);
        return res;
    }
    
    void modify(int l, int r, int v) { modify(1, 1, (n+m)<<1, l+m+n, r+m+n, v); }
    int query(int l, int r) { return query(1, 1, (n+m)<<1, l+m+n, r+m+n); }
    
    int main() {
        n = read(); m = read(); b = &buf[m];
        build(1, 1, (n+m)<<1);
        rep(i, 1, n) b[a[i] = read()]++;
        rep(i, 1, n) modify(i-b[i]+1, i, 1);
        rep(i, 1, m) {
            int p = read(), v = read();
            if (p) {
                if (a[p]-offset <= n) modify(a[p]-b[a[p]]+1, a[p]-b[a[p]]+1, -1);
                b[a[p]]--, b[a[p] = v+offset]++;
                if (a[p]-offset <= n) modify(a[p]-b[a[p]]+1, a[p]-b[a[p]]+1, 1);
            } else {
                if (v > 0 && b[n+offset]) modify(n+offset-b[n+offset]+1, n+offset, -1);
                offset -= v;
                if (v < 0 && b[n+offset]) modify(n+offset-b[n+offset]+1, n+offset, 1);
            }
            printf("%d
    ", query(offset+1, offset+n));
        }
        return 0;
    }
    
  • 相关阅读:
    zookeeper安装(linux)
    rabbitmq安装(linux)遇到 很多坑
    关于mysql数据库连接异常处理
    git放弃修改&放弃增加文件
    git使用常见问题
    base64字符串转化成图片
    Block小结
    关闭selinux
    Ctrl快捷键和vim快捷键
    正则表达式扩展正则
  • 原文地址:https://www.cnblogs.com/ac-evil/p/12544193.html
Copyright © 2011-2022 走看看