• 自嗨测试赛5


    A Beautiful

    题目大意 : 一个n×n的矩阵,每行是排列,要求相邻两行要错排,给出一个矩阵问按字典序从小到大排序后的排名

    • 枚举在哪一行字典序小,前面的与给的一样,后面的任意排,再枚举这一行中哪一个字典序小,前面的与给的一样,后面的任意排

    • 这样就能求出比这个矩阵字典序小的有多少个

    • 具体求的时候,第一行是个排列,康托展开模板,没听说过应该也会

    • 后面的行都得错排,枚举哪一个的时候后面的不一定都要错排,要统计一下需要错排的有几个,然后用扩展错排,打表可以找到规律,网上一篇题解上的式子是错的。

    Code

    Show Code
    #include <cstdio>
    
    using namespace std;
    const int N = 2005, M = 19990921;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, a[N][N], f[N][N], p[N], fac[N], ans;
    //f[i][j]:i个数j个限制的错排
    
    struct Tree {
        int t[N], v[N];
        void Add(int x, int w) {
            if (w == -1 && !v[x]) return; v[x] ^= 1;
            for (; x <= n; x += x & -x) t[x] += w;
        }
        int Ask(int x, int w = 0) {
            for (; x; x -= x & -x) w += t[x];
            return w;
        }
        void Init() {
            for (int i = 1; i <= n; ++i) t[i] = i&-i, v[i] = 1;
        }
    }t1, t2;
    
    int main() {
        freopen("beautiful.in", "r", stdin);
        freopen("beautiful.out", "w", stdout);
        n = read();
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                a[i][j] = read();
        f[0][0] = 1; f[1][1] = 0; f[2][2] = 1; 
        for (int i = 3; i <= n; ++i)
            f[i][i] = 1ll * (i - 1) * (f[i-1][i-1] + f[i-2][i-2]) % M;
        for (int i = 1; i <= n; ++i)
            for (int j = i-1; j >= 0; --j)
                if ((f[i][j] = f[i][j+1] + f[i-1][j]) >= M) f[i][j] -= M;
        fac[0] = p[0] = 1;
        for (int i = 1; i <= n; ++i) {
            fac[i] = 1ll * fac[i-1] * i % M;
            p[i] = 1ll * p[i-1] * f[n][n] % M;
        }
        //for (int i = 0; i <= n; ++i, puts("")) for (int j = 0; j <= i; ++j) printf("%d ", f[i][j]);
        t1.Init();
        for (int j = 1; j <= n; ++j)
            t1.Add(a[1][j], -1), ans = (ans + 1ll * t1.Ask(a[1][j]) * fac[n-j]) % M;
        ans = 1ll * ans * p[n-1] % M;
        for (int i = 2; i <= n; ++i) {
            int sum = 0; t1.Init(); t2.Init();
            for (int j = 1; j <= n; ++j) {
                int tot, cnt, tmp; 
                //tot 这个位置能选多少个
                //tmp 有多少个限制
                //cnt 这个位置多少种选法会使限制-1
                t1.Add(a[i][j], -1); tot = t1.Ask(a[i][j]);
                if (a[i-1][j] < a[i][j] && t1.v[a[i-1][j]]) tot--;
                t2.Add(a[i-1][j], -1); tmp = t2.Ask(n);
                cnt = t2.Ask(a[i][j] - 1);
                sum = (sum + 1ll * cnt * f[n-j][tmp-1] + 1ll * (tot - cnt) * f[n-j][tmp]) % M;
                t2.Add(a[i][j], -1);
            }
            ans = (ans + 1ll * sum * p[n-i]) % M;
        }
        printf("%d
    ", ans + 1);
        return 0;
    }
    

    B Exchange

    题目大意 : 支持区间加,区间求和,交换区间

    • 开始想的FHQ,但是没学过,突然就想到lct维护,当时感觉特别妙,交换区间的时候Cut四次,然后Link四次,考场上调了3个多小时没调出来

    • 正解是动态开点线段树,因为交换的区间有特殊性质,初始区间设为0到2^k-1,交换的时候只需要交换两个节点,真的是秒极了

    • 交换完记得Pushup一下,不然查询的时候会出错

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    #define ls t[rt].l
    #define rs t[rt].r
    
    using namespace std;
    typedef long long ll;
    const int N = 2.5e7 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; (c < '0' || c > '9'); c = getchar()) if (c == '-') f = -1;
        for (;!(c < '0' || c > '9'); c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    int n, m, M, opt, trc = 1;
    ll ans;
    
    struct Tree {
        int l, r, tag; ll s;
    }t[N];
    
    void Update(int rt, int l, int r, int w) {
        t[rt].s += 1ll * w * (r - l + 1); t[rt].tag += w;
    }
    
    void Pushdown(int rt, int l, int r) {
        if (!ls) ls = ++trc;
        if (!rs) rs = ++trc;
        if (!t[rt].tag) return;
        int mid = l + r >> 1; 
        Update(ls, l, mid, t[rt].tag); 
        Update(rs, mid+1, r, t[rt].tag); 
        t[rt].tag = 0;
    }
    
    void Add(int rt, int l, int r, int x, int y, int w) {
        if (x <= l && r <= y) return Update(rt, l, r, w);
        int mid = l + r >> 1; Pushdown(rt, l, r);
        if (x <= mid) Add(ls, l, mid, x, y, w);
        if (y >  mid) Add(rs, mid+1, r, x, y, w);
        t[rt].s = t[ls].s + t[rs].s;
    }
    
    int Find(int rt, int l, int r, int x, int y) {
        if (x <= l && r <= y) return rt;
        int mid = l + r >> 1; Pushdown(rt, l, r);
        if (y <= mid) return Find(ls, l, mid, x, y);
        else return Find(rs, mid + 1, r, x, y);
    }
    
    ll Ask(int rt, int l, int r, int x, int y) {
        if (x <= l && r <= y) return t[rt].s;
        int mid = l + r >> 1; ll ans = 0; Pushdown(rt, l, r);
        if (x <= mid) ans = Ask(ls, l, mid, x, y);
        if (y > mid) ans += Ask(rs, mid + 1, r, x, y);
        return ans;
    }
    
    int main() {
        freopen("exchange.in", "r", stdin);
        freopen("exchange.out", "w", stdout);
        n = read(); m = read(); opt = read(); M = n + 1;
        for (int i = 1; i <= n; i *= 2)
            if (i * 2 - 1 > n) n = i * 2 - 1;
        while (m--) {
            int od = read(), l = read(), r = read();
            if (opt) l = (l + ans) % M, r = (r + ans) % M;
            if (od == 1) {
                int x = read();
                if (opt) x = (x + ans) % M;
                Add(1, 0, n, l, r, x);
            }
            else if (od == 2) {
                int x = read();
                if (opt) x = (x + ans) % M;
                x = 1 << x; l *= x; r *= x;
                swap(t[Find(1, 0, n, l, l + x - 1)], t[Find(1, 0, n, r, r + x - 1)]);
                Add(1, 0, n, l, l + x - 1, 0);
                Add(1, 0, n, r, r + x - 1, 0); 
            }
            else printf("%lld
    ", ans = Ask(1, 0, n, l, r));
        }
        return 0;
    }
    

    C Embedding Enumeration (Unaccepted)

    题目大意 :

    • 巨型分类讨论dp

    Code

    Show Code
  • 相关阅读:
    【Flex】Fluorinefx在IIS 5.1下响应很慢
    【Oracle】客户端查询数据库最近执行的SQL语句
    【Flex】Cairngorm中View层的交互
    ubuntu安装python3.6提示 无法修正错误 的 解决
    linux 如何杀死,暂停,继续一个后台进程
    Ubuntu虚拟机双网卡的配置(Uboot,tftp下载)(原创)
    Ubuntu的dpkg命令用法
    Vim Plus的搭建,并完善相关插件,打造最强vim编辑器(原创)
    ubuntu下minicom的使用方法(类似win的超级终端)
    Ubuntu安装ssh
  • 原文地址:https://www.cnblogs.com/shawk/p/14526074.html
Copyright © 2020-2023  润新知