• Solution -「ABC 217」题解


    D - Cutting Woods

    记录每一个切割点,每次求前驱后驱就好了,注意简单判断一下开闭区间。

    考场上采用的 FHQ_Treap 无脑莽。

    #include <cstdio>
    #include <cstdlib>
    using namespace std;
     
    typedef long long LL;
    LL Max(LL x, LL y) { return x > y ? x : y; }
    LL Min(LL x, LL y) { return x < y ? x : y; }
    LL Abs(LL x) { return x < 0 ? -x : x; }
     
    int read() {
        int k = 1, x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
     
    LL read_LL() {
        int k = 1;
    	LL x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
     
    void write(LL x) {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9)
            write(x / 10);
        putchar(x % 10 + '0');
    }
     
    void print(LL x, char s) {
        write(x);
        putchar(s);
    }
     
    // Fhq-Treap
    const int MAXN = 2e5 + 5;
     
    struct Fhq_Treap {
        struct Fhq_Node {
            int l, r, val, key, size;
    #define lson tr[p].l
    #define rson tr[p].r
            Fhq_Node() {}
            Fhq_Node(int L, int R, int Val, int Key, int Size) {
                l = L;
                r = R;
                val = Val;
                key = Key;
                size = Size;
            }
        } tr[MAXN];
        int tot, root;
     
        Fhq_Treap() {
            tot = 0, root = 0;
        }
     
        int Get(int val) {
            tr[++tot] = Fhq_Node(0, 0, val, rand(), 1);
            return tot;
        }
     
        void Push_Up(int p) { tr[p].size = tr[lson].size + tr[rson].size + 1; }
     
        void Split(int p, int val, int &x, int &y) {
            if (!p) {
                x = 0, y = 0;
                return;
            }
            if (tr[p].val <= val) {
                x = p;
                Split(rson, val, rson, y);
            } else {
                y = p;
                Split(lson, val, x, lson);
            }
            Push_Up(p);
        }
     
        int Merge(int x, int y) {
            if (!x || !y)
                return x + y;
            if (tr[x].key <= tr[y].key) {
                tr[x].r = Merge(tr[x].r, y);
                Push_Up(x);
                return x;
            } else {
                tr[y].l = Merge(x, tr[y].l);
                Push_Up(y);
                return y;
            }
        }
     
        void Insert(int val) {
            int x, y;
            Split(root, val, x, y);
            root = Merge(Merge(x, Get(val)), y);
        }
     
        void Delete(int val) {
            int x, y, z;
            Split(root, val, x, z);
            Split(x, val - 1, x, y);
            y = Merge(tr[y].l, tr[y].r);
            root = Merge(Merge(x, y), z);
        }
     
        int Get_Rank(int val) {
            int x, y, ret;
            Split(root, val - 1, x, y);
            ret = tr[x].size + 1;
            root = Merge(x, y);
            return ret;
        }
     
        int Get_Val(int Rank) {
            int p = root;
            while (p) {
                if (tr[lson].size + 1 == Rank)
                    return tr[p].val;
                else if (Rank <= tr[lson].size)
                    p = lson;
                else {
                    Rank -= (tr[lson].size + 1);
                    p = rson;
                }
            }
            return 0;
        }
     
        int Get_Pre(int val) {
            int x, y, p;
            Split(root, val - 1, x, y);
            p = x;
            while (rson) p = rson;
            int ret = tr[p].val;
            root = Merge(x, y);
            return ret;
        }
     
        int Get_Next(int val) {
            int x, y, p;
            Split(root, val, x, y);
            p = y;
            while (lson) p = lson;
            int ret = tr[p].val;
            root = Merge(x, y);
            return ret;
        }
    #undef lson
    #undef rson
    } tree;
     
    int main() {
    	int l = read(), q = read();
    	tree.Insert(0);
    	tree.Insert(l);
    	for(int i = 1, opt, x; i <= q; i++) {
    		opt = read(), x = read();
    		if(opt == 1)
    			tree.Insert(x);
    		else
    			print(tree.Get_Next(x) - tree.Get_Pre(x), '
    ');
    	}
    	return 0;
    }
    

    E - Sorting Queries

    将所有的插入操作先存进一个临时序列。

    在遇到排序操作时再处理这些序列里的元素。

    具体来说就是直接丢进优先队列。也可以学我赛时直接 copy D 的 code 来改。

    #include <queue>
    #include <cstdio>
    using namespace std;
     
    typedef long long LL;
    LL Max(LL x, LL y) { return x > y ? x : y; }
    LL Min(LL x, LL y) { return x < y ? x : y; }
    LL Abs(LL x) { return x < 0 ? -x : x; }
     
    int read() {
        int k = 1, x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
     
    LL read_LL() {
        int k = 1;
    	LL x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
     
    void write(LL x) {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9)
            write(x / 10);
        putchar(x % 10 + '0');
    }
     
    void print(LL x, char s) {
        write(x);
        putchar(s);
    }
     
    const int MAXN = 2e5 + 5;
     
    int num[MAXN], len = 0, tot = 1;
    priority_queue<int, vector<int>, greater<int> > q;
     
    int main() {
    	int n = read();
    	for(int i = 1, opt; i <= n; i++) {
    		opt = read();
    		if(opt == 1) {
    			int x = read();
    			num[++len] = x;
    		}
    		else if(opt == 2) {
    			if(!q.empty()) {
    				print(q.top(), '
    ');
    				q.pop();
    			}
    			else {
    				print(num[tot], '
    ');
    				tot++;
    			}
    		}
    		else {
    			for(int i = tot; i <= len; i++)	
    				q.push(num[i]);
    			tot = 1, len = 0;
    		}
    	}
    	return 0;
    }
    

    F - Make Pair

    小清新的区间 dp 题。

    相邻删除这样的操作就应该往区间 dp 上去想。

    定义 (f(i, j)) 表示将区间 ([i, j]) 匹配完的方案数,显然需要满足 (2 mid r - l + 1)

    可得:

    [f(i, j) = sum_{k in (l, r], 2 | k - i + 1} f(i + 1, k) imes f(k + 1, j) imes inom{frac {j - i + 1} {2}}{frac {j - k + 1} {2}} ]

    其中 (k) 同学和 (i) 同学关系友好,且对于任意 (i),若 (0 leq i leq n),有 (f(i, i + 1) = 1)

    其中组合数可以理解为我们共有 (frac {j - i + 1} {2}) 个盒子(盒子间被认为是不同的),且我们有 (frac {k - i - 1} {2})(a) 球,(1)(b) 球,和 (frac {j - k} {2})(c) 球(同种类的球被认为是相同的,这是因为在上面的转移柿子中我们已经考虑了球种类内部的情况),且 (b) 球放入的盒子编号必须大于任意一个 (a) 球放入的盒子编号。

    感性理解一下其实就是我们在所有的盒子中选 (frac {j - k} {2}) 个出来放 (c) 球。

    时间复杂度 (O(n^3))

    #include <cstdio>
    
    typedef long long LL;
    int Max(int x, int y) { return x > y ? x : y; }
    int Min(int x, int y) { return x < y ? x : y; }
    int Abs(int x) { return x < 0 ? -x : x; }
    
    int read() {
        int x = 0, k = 1;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while ('0' <= s && s <= '9') {
            x = (x << 3) + (x << 1) + (s - '0');
            s = getchar();
        }
        return x * k;
    }
    
    void write(LL x) {
        if (x < 0) {
            x = -x;
            putchar('-');
        }
        if (x > 9)
            write(x / 10);
        putchar(x % 10 + '0');
    }
    
    void print(LL x, char s) {
        write(x);
        putchar(s);
    }
    
    const int MAXN = 4e2 + 5;
    const int mod = 998244353;
    
    bool w[MAXN][MAXN]; 
    LL q[MAXN], sq[MAXN], dp[MAXN][MAXN];
     
    LL A (int x, int y) { return q[x] * sq[x - y] % mod;}
     
    LL C (int x, int y) { return A(x, y) * sq[y] % mod;}
     
    LL Quick_Pow(LL a, LL b) {
    	LL res = 1;
    	while(b) {
    		if(b & 1)
    			res = res * a % mod;
    		a = a * a % mod;
    		b >>= 1;		
    	}
    	return res % mod;
    }
    
    int main() {
    	int n = read(), m = read();
    	q[0] = 1, sq[0] = 1;
    	for(int i = 1; i <= (n << 1); i++) {
    		q[i] = q[i - 1] * i % mod;
    		sq[i] = Quick_Pow(q[i], mod - 2);
    	}
    	for(int i = 1, a, b; i <= m; i++) {
    		a = read(), b = read();
    		w[a][b] = w[b][a] = true;
    	}
    	for(int i = 1; i <= (n << 1) + 1; i++)
    		dp[i][i - 1] = 1;
    	for(int len = 2; len <= (n << 1); len += 2) 
    		for(int l = 1; l + len - 1 <= (n << 1); l++) {
    			int r = l + len - 1;
    			for(int k = l + 1; k <= r; k += 2)
    				if(w[l][k])
    					dp[l][r] = (dp[l][r] + dp[l + 1][k - 1] * dp[k + 1][r] % mod * C(len / 2, (r - k + 1) / 2) % mod) % mod;
    		}
    	print(dp[1][n << 1], '
    ');
    	return 0;
    }
    

    G - Groups

    还是一道 dp 呢。

    我们定义 (f(i, j)) 表示分完前 (i) 个数且当前分了 (j) 个组。

    考虑当前数的两种决策。

    第一种,新开一个组,即方案数为 (f(i - 1, j - 1))

    第二种,不开新的组而是丢进已存在的组,不难发现当前数可以丢入的组共有 (j - t(i, i mod m)) 个,其中 (t(x, y) = sum_{i = 1}^{x} [i mod m = y])

    故可得,(f(i, j) = f(i - 1, j - 1) + f(i - 1, j) imes (j - t(i, i mod m)))

    初始状态为 (f(0, 0) = 1)。其他的比如 (t(x, y)) 的转移啦、答案状态啦就很简单了嘛,时间复杂度 (O(n^2))

    #include <cstdio>
    
    typedef long long LL;
    LL Max(LL x, LL y) { return x > y ? x : y; }
    LL Min(LL x, LL y) { return x < y ? x : y; }
    LL Abs(LL x) { return x < 0 ? -x : x; }
    
    int read() {
        int k = 1, x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
    
    LL read_LL() {
        int k = 1;
    	LL x = 0;
        char s = getchar();
        while (s < '0' || s > '9') {
            if (s == '-')
                k = -1;
            s = getchar();
        }
        while (s >= '0' && s <= '9') {
            x = (x << 3) + (x << 1) + s - '0';
            s = getchar();
        }
        return x * k;
    }
    
    void write(LL x) {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x > 9)
            write(x / 10);
        putchar(x % 10 + '0');
    }
    
    void print(LL x, char s) {
        write(x);
        putchar(s);
    }
    
    const int MAXN = 5e3 + 5;
    const int mod = 998244353; 
    
    int t[MAXN];
    LL dp[MAXN][MAXN];
    
    int main() {
    	int n = read(), m = read();
    	dp[0][0] = 1;
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= n; j++) 
    			dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j] * ((j - t[i % m] + mod) % mod) % mod) % mod;	
    		t[i % m]++;	
    	}
    	for(int i = 1; i <= n; i++)
    		print(dp[n][i], '
    ');
    	return 0;
    }
    

    H - Snuketoon

    不会了不会了不会了 /fad。

  • 相关阅读:
    QTP的那些事有关正则表达式匹配对象的一个小注意点
    ant 中用到的各种变量的方式
    Host prepare for your automation work
    mybatis3进行模糊查询的总结
    QTP的那些事—QTP11+QC11框架整理源码(个人原创)2012615更新版
    QTP的那些事场景恢复的使用(加入场景恢复却不起作用)
    hudson搭建第一步环境配置
    SQL SERVER 查看和杀掉死锁的进程代码
    SQL Server创建和使用临时表(转)
    从HTML代码中提取文字,去掉HTML的标记
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/15233984.html
Copyright © 2020-2023  润新知