zoukankan      html  css  js  c++  java
  • 2019杭电多校第二场

    2019杭电多校第二场

    太菜了,被学弟暴打

    1002. Beauty of Unimodal Sequence

    upsolved

    要求输出字典序最小和最大的最长单峰子序列

    对于每一个位置,维护以这个位置结尾的前缀/后缀最长上升/单峰子序列长度,然后贪心输出(如果只要求长度正反求LIS就好了)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 3e5 + 10;
    
    int n, a[N];
    
    struct Seg_Tree {
    	int mx[N << 2];
    	void init(int rt = 1, int l = 1, int r = n + 2) {
    		mx[rt] = 0;
    		if(l == r) return;
    		int mid = l + r >> 1;
    		init(rt << 1, l, mid);
    		init(rt << 1 | 1, mid + 1, r);
    	}
    	void pushup(int rt) {
    		mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
    	}
    	void update(int rt, int l, int r, int pos, int val) {
    		if(l == r) {
    			mx[rt] = max(mx[rt], val);
    			return;
    		}
    		int mid = l + r >> 1;
    		if(pos <= mid)
    			update(rt << 1, l, mid, pos, val);
    		else
    			update(rt << 1 | 1, mid + 1, r, pos, val);
    		pushup(rt);
    	}
    	int query(int rt, int l, int r, int L, int R) {
    		if(L <= l && r <= R)
    			return mx[rt];
    		int mid = l + r >> 1, ans = 0;
    		if(L <= mid)
    			ans = max(ans, query(rt << 1, l, mid, L, R));
    		if(R > mid)
    			ans = max(ans, query(rt << 1 | 1, mid + 1, r, L, R));
    		return ans;
    	}
    }zero, one;
    
    int dp[2][N][2], len;
    vector<int> ans[2], all, up[N], down[N];
    
    void init() {
    	len = 0;
    	zero.init();
    	one.init();
    	all.clear();
    	ans[0].clear();
    	ans[1].clear();
    	for(int i = 0; i <= n + 1; ++i)
    		up[i].clear(), down[i].clear();
    }
    
    int main() {
    	while(~scanf("%d", &n)) {
    		init();
    		for(int i = 1; i <= n; ++i) {
    			scanf("%d", &a[i]);
    			all.push_back(a[i]);
    		}
    		all.push_back(0);
    		all.push_back(0x3f3f3f3f);
    		sort(all.begin(), all.end());
    		all.erase(unique(all.begin(), all.end()), all.end());
    		for(int i = 1; i <= n; ++i) {
    			a[i] = lower_bound(all.begin(), all.end(), a[i]) - all.begin() + 1;
    		}
    		for(int i = 1; i <= n; ++i) {
    			dp[0][i][0] = zero.query(1, 1, n + 2, 1, a[i] - 1) + 1;
    			dp[0][i][1] = max(one.query(1, 1, n + 2, a[i] + 1, n + 2) + 1, dp[0][i][0]);
    			zero.update(1, 1, n + 2, a[i], dp[0][i][0]);
    			one.update(1, 1, n + 2, a[i], dp[0][i][1]);
    		}
    		zero.init(); one.init();
    		for(int i = n; i; --i) {
    			dp[1][i][0] = zero.query(1, 1, n + 2, 1, a[i] - 1) + 1;
    			dp[1][i][1] = max(one.query(1, 1, n + 2, a[i] + 1, n + 2) + 1, dp[1][i][0]);
    			zero.update(1, 1, n + 2, a[i], dp[1][i][0]);
    			one.update(1, 1, n + 2, a[i], dp[1][i][1]);
    		}
    		for(int i = 1; i <= n; ++i) {
    			len = max(len, dp[0][i][0] + dp[1][i][1] - 1);
    		}
    		for(int i = 1; i <= n; ++i) {
    			assert(len >= dp[0][i][1] + dp[1][i][0] - 1);
    		}
    		for(int i = 1; i <= n; ++i) {
    			if(dp[0][i][0] + dp[1][i][1] - 1 == len) {
    				up[dp[0][i][0]].push_back(i);
    			}
    			if(dp[0][i][1] + dp[1][i][0] - 1 == len) {
    				down[dp[1][i][0]].push_back(i);
    			}
    		}
    		int cur = 0, flag = 0;
    		for(int i = 1; i <= len; ++i) {
    			if(!flag) {
    				vector<int> &v = up[i];
    				int p = upper_bound(v.begin(), v.end(), cur) - v.begin();
    				if(p == v.size() || a[v[p]] <= a[cur]) {
    					flag = 1;
    				}
    				else {
    					vector<int> &vv = down[len - i + 1];
    					int pp = upper_bound(v.begin(), v.end(), cur) - v.begin();
    					if(pp != vv.size() && a[vv[pp]] < a[cur] && vv[pp] < v[p]) {
    						flag = 1;
    					}
    					else {
    						cur = v[p];
    						ans[0].push_back(v[p]);
    					}
    				}
    			}
    			if(flag) {
    				vector<int> &v = down[len - i + 1];
    				int p = upper_bound(v.begin(), v.end(), cur) - v.begin();
    				assert(a[v[p]] < a[cur]);
    				assert(p < v.size());
    				cur = v[p];
    				ans[0].push_back(v[p]);
    			}
    		}
    		cur = flag = 0;
    		for(int i = 1; i <= len; ++i) {
    			if(!flag) {
    				vector<int> &v = up[i];
    				int p = lower_bound(v.begin(), v.end(), cur, [&](int i, int j){return a[i] > a[j];}) - v.begin() - 1;
    				if(p < 0 || a[v[p]] <= a[cur]) {
    					flag = 1;
    				}
    				else {
    					cur = v[p];
    					ans[1].push_back(v[p]);
    				}
    			}
    			if(flag) {
    				vector<int> &v = down[len - i + 1];
    				int p = lower_bound(v.begin(), v.end(), cur, [&](int i, int j){return a[i] < a[j];}) - v.begin() - 1;
    				assert(p >= 0);
    				assert(a[v[p]] < a[cur]);
    				cur = v[p];
    				ans[1].push_back(v[p]);
    			}
    		}
    		for(int _ = 0; _ < 2; ++_) {
    			for(int i = 0; i < len; ++i)
    				printf("%d%c", ans[_][i], " 
    "[i + 1 == len]);
    		}
    	}
    	return 0;
    }
    

    1005. Everything Is Generated In Equal Probability

    solved at 01:45(+1)

    求当前序列的逆序对数并且将当前序列随机替换成一个子序列((2^n))种,递归处理每次结果相加直到序列为空为止

    每次给定一个({ m N}), 你随机取一个(nin[1,{ m N}]),然后随机取一个(n)个数的排列作为初始序列,求总逆序对数的期望

    (f(n))代表长为(n)的序列的期望

    显然$$f(n) = frac {n(n-1)} 4 + sumlimits_{i = 0}^{n}frac {C_n^i} {2^n}f(i)$$

    (n)只有(3000),(n^2)递推即可,最后再求个前缀和

    群里有老哥一眼看出答案是(frac {n^2-1} 9) ....

    1006. Fantastic Magic Cube

    upsolved

    题意转化之后就是你有一个(n*n*n)的立方体,每个(1*1*1)的小立方体都有自己的权值(权值为三个坐标的异或),你每次沿着一个方向把一个立方体切成两个立方体,获得的价值是两个立方体的权值和的乘积,你需要把它们都切成(1*1*1)的,求最大价值

    听了dls题解,发现是个阅读理解,不管怎么切都是一样的

    考虑两个不同的小立方体,它们的权值乘积一定被加到了最终的价值里,并且只加了一次

    于是只要(FWT)求出每个权值的小立方体有多少个然后求一求和就好了

    #include <bits/stdc++.h>
    using namespace std;
    using LL = long long;
    const int mod = 998244353, N = 1048576 + 10, g = 3;
    
    LL qp(LL a, LL n) {
    	LL res = 1;
    	while(n) {
    		if(n & 1) 
    			res = res * a % mod;
    		a = a * a % mod;
    		n >>= 1;
    	}
    	return res;
    }
    
    const int inv2 = qp(2, mod - 2);
    
    void FWT(int a[], int n) {  
        for(int d = 1; d < n; d <<= 1)  
            for(int m = d << 1, i = 0; i < n; i += m)  
                for(int j = 0; j < d; ++j) {  
                    int x = a[i + j], y = a[i + j + d];  
                    a[i + j] = (x + y) % mod, a[i + j + d] = (x - y + mod) % mod;   
                }  
    }  
    
    void IFWT(int a[], int n)   {  
        for(int d = 1; d < n; d <<= 1)  
            for(int m = d << 1, i = 0; i < n; i += m)  
                for(int j = 0; j < d; ++j) {  
                    int x = a[i + j], y = a[i + j + d];  
                    a[i + j] = 1LL * (x + y) * inv2 % mod, a[i + j + d] = (1LL * (x - y) * inv2 % mod + mod) % mod; 
                }  
    } 
    
    int n, a[N], m;
    LL sum, ans;
    
    int main() {
    	while(~scanf("%d", &n)) {
    		m = n;
    		sum = ans = 0;
    		for(; m & (m - 1); m += m & -m);
    		for(int i = 0; i < m; ++i) 
    			a[i] = 0;
    		for(int i = 0; i < n; ++i)
    			a[i] = 1;
    		FWT(a, m);
    		for(int i = 0; i < m; ++i)
    			a[i] = 1LL * a[i] * a[i] % mod * a[i] % mod;
    		IFWT(a, m);
    		for(int i = 0; i < m; ++i)
    			sum = (sum + 1LL * i * a[i]) % mod;
    		for(int i = 0; i < m; ++i)
    			ans = (ans + (1LL * i * a[i] % mod * (sum - i) % mod + mod) % mod) % mod;
    		printf("%lld
    ", ans * inv2 % mod);
    	}
    	return 0;
    }
    

    1009. I Love Palindrome String

    待补, PAM待学

    1010. Just Skip The Problem

    solved at 00:31

    直接输出(n!)就好了,(1)特判掉(不过我看有的人没特判就过了,怕不是没这数据。。。)

    1011. Keen on Everything But Triangle

    solved at 00:44

    (Q)次询问一个区间里的数能构成的最大周长的三角形

    因为数据范围是(1e9)所以大概四十几个数就一定能构成三角形,从大到小排序,先找(123),不行就(234),找个四十几次就行了

    主席树实现的,线段树维护前(45)大暴力合并据说也可以

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    const int MAXN = 100010;
    struct node {
    	int l, r, sum;
    }Tree[MAXN * 30];
    int root[MAXN];
    
    struct num {
    	int x, id;
    	bool operator < (const num &rhs) const {
    		return x < rhs.x;
    	}
    }a[MAXN];
    
    int rnk[MAXN];
    int n, m, i, j, k, cnt, l, r, x, y, z;
    
    void init() {
    	cnt = 0;
    	root[0] = 0;
    	Tree[0].l = Tree[0].r = Tree[0].sum = 0;
    }
    
    void update(int &rt, int l, int r, int num) {
    	Tree[++cnt] = Tree[rt];
    	rt = cnt;
    	Tree[rt].sum++;
    	if(l == r)
    		return;
    	int mid = l + r >> 1;
    	if(num <= mid)
    		update(Tree[rt].l, l, mid, num);
    	else
    		update(Tree[rt].r, mid + 1, r, num);
    }
    
    int query(int i, int j, int k, int l, int r) {
    	if(l == r)
    		return l;
    	int mid = l + r >> 1;
    	int d = Tree[Tree[j].l].sum - Tree[Tree[i].l].sum;
    	if(k <= d)
    		return query(Tree[i].l, Tree[j].l, k, l, mid);
    	else
    		return query(Tree[i].r, Tree[j].r, k - d, mid + 1, r);
    }
    
    int main() {
    	while(~scanf("%d %d", &n, &m)) {
    		init();
    		for(int i = 1; i <= n; ++i) {
    			scanf("%d", &a[i].x);
    			a[i].id = i;
    		}
    		sort(a + 1, a + n + 1);
    		for(int i = 1; i <= n; ++i) {
    			rnk[a[i].id] = i;
    		}
    		for(int i = 1; i <= n; ++i) {
    			root[i] = root[i - 1];
    			update(root[i], 1, n, rnk[i]);
    		}
    		while(m--) {
    			scanf("%d %d", &l, &r);
    			if(r - l < 2) {
    				printf("-1
    ");
    				continue;
    			}
    			cnt = r - l + 1;
    			x = a[query(root[l - 1], root[r], cnt, 1, n)].x;
    			y = a[query(root[l - 1], root[r], cnt - 1, 1, n)].x;
    			z = a[query(root[l - 1], root[r], cnt - 2, 1, n)].x;
    			if(x < y + z) {
    				printf("%lld
    ", 0LL + x + y + z);
    				continue;
    			}
    			bool flag = 0;
    			for(int i = 3; i < cnt; ++i) {
    				x = y;
    				y = z;
    				z = a[query(root[l - 1], root[r], cnt - i, 1, n)].x;
    				if(x < y + z) {
    					flag = 1;
    					printf("%lld
    ", 0LL + x + y + z);
    					break;
    				}
    			}
    			if(!flag) {
    				printf("-1
    ");
    			}
    		}
    	}
    	return 0;
    }
    
    

    1012. Longest Subarray

    upsolved

    自闭题

    求最长的连续子序列满足序列里出现的数都至少出现了(k)

    枚举右端点,线段树维护不合法的区间,每次询问最左边的合法位置即可

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 10;
    
    int mn[N << 2], lazy[N << 2];
    
    void pushdown(int rt) {
    	if(lazy[rt]) {
    		lazy[rt << 1] += lazy[rt];
    		lazy[rt << 1 | 1] += lazy[rt];
    		mn[rt << 1] += lazy[rt];
    		mn[rt << 1 | 1] += lazy[rt];
    		lazy[rt] = 0;
    	}
    }
    
    void pushup(int rt) {
    	mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]);
    }
    
    void build(int rt, int l, int r) {
    	lazy[rt] = mn[rt] = 0;
    	if(l == r)
    		return;
    	int mid = l + r >> 1;
    	build(rt << 1, l, mid);
    	build(rt << 1 | 1, mid + 1, r);
    }
    
    void update(int rt, int	l, int r, int L, int R, int val) {
    	if(L <= l && r <= R) {
    		mn[rt] += val;
    		lazy[rt] += val;
    		return;
    	}
    	pushdown(rt);
    	int mid = l + r >> 1;
    	if(L <= mid)
    		update(rt << 1, l, mid, L, R, val);
    	if(R > mid)
    		update(rt << 1 | 1, mid + 1, r, L, R, val);
    	pushup(rt);
    }
    
    int query(int rt, int l, int r) {
    	if(mn[rt] > 0) return 0;
    	if(l == r) return l;
    	pushdown(rt);
    	int mid = l + r >> 1;
    	if(mn[rt << 1] == 0)
    		return query(rt << 1, l, mid);
    	return query(rt << 1 | 1, mid + 1, r);
    }
    
    int a[N], n, c, k, ans, i, j, x, y;
    vector<int> pos[N];
    
    int main() {
    	while(~scanf("%d%d%d", &n, &c, &k)) {
    		if(k == 1) {
    			for(int i = 1; i <= n; ++i)
    				scanf("%*d");
    			printf("%d
    ", n);
    			continue;
    		}
    		build(1, 1, n);
    		ans = 0;
    		for(i = 1; i <= n; ++i) {
    			scanf("%d", &a[i]);
    			if(pos[a[i]].empty()) {
    				update(1, 1, n, 1, i, 1);
    				pos[a[i]].push_back(i);
    			}
    			else {
    				x = pos[a[i]].size() - k;
    				y = pos[a[i]].back();
    				if(x < 0) {
    					update(1, 1, n, 1, y, -1);
    				}
    				else {
    					update(1, 1, n, pos[a[i]][x] + 1, y, -1);
    				}
    				pos[a[i]].push_back(i);
    				x = pos[a[i]].size() - k;
    				y = pos[a[i]].back();
    				if(x < 0) {
    					update(1, 1, n, 1, y, 1);
    				}
    				else {
    					update(1, 1, n, pos[a[i]][x] + 1, y, 1);
    				}
    			}
    			j = query(1, 1, n);
    			if(j) ans = max(ans, i - j + 1);
    		}
    		for(int i = 1; i <= c; ++i)
    			pos[i].clear();
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    1007dls发了ppt, 估计是学不会,1008队友补了,1009看什么时候有时间去学

  • 相关阅读:
    现代软件工程的构建之法
    How do I Check for Duplicate Items in a ListView?
    (转)aspxgridview记录的批量修改
    vs2010简体中文旗舰版智能感知,中文提示,英文提示变化的问题
    (转)怎样成为一名Android开发者
    It’s Not Too Late to Learn How to Code
    (转)手机屏幕VGA QVGA HVGA WVGA区别
    (转)CodeSmithSchemaExplorer类结构详细介绍
    (转)C#控件命名规范
    DataReader 绑定DataGridView的方式
  • 原文地址:https://www.cnblogs.com/tusikalanse/p/11247250.html
Copyright © 2011-2022 走看看