• Educational Codeforces Round 97 简要题解


    Educational Codeforces Round 97 简要题解

    缺省源

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x, char ed = '
    ') {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar(ed);
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    

    A. Marketing Scheme

    直接判断 (l imes 2 ge r) 即可。

    B. Reverse Binary Strings

    这题让好多人想了一会(我也,考虑对序列异或差分,最终序列要求全部事 1,每次 reverse 可以发现只有两端的值变,所以每次可以同时消掉两个 0

    C. Chef Monocarp

    简单 dp 即可

    D. Minimal Height Tree

    模拟 bfs 即可,找到最长的连续段当作一串儿子挂在一个节点上。

    const int N = 200050;
    int dep[N], a[N], T, n;
    int main() {
    	for (read(T); T; T--) {
    		read(n);
    		memset(dep, 0, n * 4 + 200);
    		queue<int> q; q.push(1);
    		for (int i = 1;i <= n; i++) read(a[i]);
    		for (int i = 2;i <= n; i++) {
    			int t = q.front();
    			dep[i] = dep[t] + 1, q.push(i);
    			if (a[i] >= a[i+1]) q.pop();
    		}
    		write(dep[n]);	
    	}
    	return 0;
    }
    

    E. Make It Increasing

    先考虑序列的合法情况,显然严格上升序列可以通过 (a[i] = a[i] - i) 变成非严格上升序列,所以我们先正着反着扫两遍,得出是否有解和哪些位置必须要改变,剩下的位置做最长上升子序列即可。

    const int N = 500050;
    int st[N], a[N], vis[N], n, k, tp;
    void insert(int x) {
    	if (!tp) return st[++tp] = x, void();
    	int l = 1, r = tp;
    	while (l <= r) {
    		int mid = (l + r) >> 1;
    		if (st[mid] <= x) l = mid + 1;
    		else r = mid - 1;
    	}
    	if (l > tp) st[++tp] = x;
    	else st[l] = x;
    }
    
    int main() {
    	read(n), read(k);
    	for (int i = 1;i <= n; i++) read(a[i]), a[i] -= i;
    	for (int i = 1, x;i <= k; i++) read(x), vis[x] = 1;
    	int lim = -1e9;
    	for (int i = 1;i <= n; i++) {
    		if (vis[i] == 1) {
    			if (a[i] < lim) return write(-1), 0;
    			Mx(lim, a[i]);
    		}
    		if (a[i] < lim) vis[i] = -1;
    	}
    	lim = 1e9;
    	for (int i = n;i >= 1; i--) {
    		if (vis[i] == 1) {
    			if (a[i] > lim) return write(-1), 0;
    			Mn(lim, a[i]);
    		}
    		if (a[i] > lim) vis[i] = -1;
    	}
    	memset(st, 0x3f, sizeof(st)); 
    	st[tp = 0] = 0;
    	for (int i = 1;i <= n; i++) {
    		if (vis[i]) continue;
    		insert(a[i]);
    	}
    	write(n - k - tp);
    	return 0;
    }
    

    F. Emotional Fishermen

    考后自己补出来的。

    假设我们已经获得了最终的序列,把前缀最大值看成隔板,首先两个前缀最大值 (a_i, a_{i+1}) 要满足 (2a_ile a_{i+1}),考虑其他元素 x,发现在第一个大于等于 (2x) 前缀最大值之后就可以随便填了。因此我们一个一个放前缀最大值,每放一个最大值,发现有一些元素可以随便放了,用排列算一下即可。

    dp 的过程发现还可以前缀和优化,吊打标算了

    const int N = 5005;
    const int P = 998244353;
    ll fac[N], inv[N], pre[N], dp[N], a[N], n;
    ll A(int n, int m) { return fac[n] * inv[n-m] % P; }
    int cnt[N];
    ll fpw(ll x, ll mi) {
    	ll res = 1;
    	for (; mi; mi >>= 1, x = x * x % P)
    		if (mi & 1) res = res * x % P;
    	return res;
    }
    
    int main() {
    	read(n);
    	for (int i = 1;i <= n; i++) read(a[i]);
    	fac[0] = 1;
    	for (int i = 1;i <= n; i++)
    		fac[i] = fac[i-1] * i % P;
    	inv[n] = fpw(fac[n], P - 2);
    	for (int i = n - 1; i >= 1; i--) 
    		inv[i] = inv[i+1] * (i + 1) % P;
    	inv[0] = dp[0] = 1, sort(a + 1, a + n + 1);
    	int j = 0;
    	if (a[n-1] * 2 > a[n]) return write(0), 0;
    	for (int i = 1;i <= n; i++) { 
    		while (j < n && a[j+1] * 2 <= a[i]) j++;
    		dp[i] = (A(n - 1, j) + pre[j] * inv[n - 1 - j]) % P;
    		pre[i] = (pre[i-1] + dp[i] * fac[n - j - 2]) % P;
    	} 
    	write(dp[n]);
    	return 0;
    }
    

    G. Death DBMS

    套路模板题,链剖 + AC 自动姬,考场上竟然码出来了,我也是码农

    jly 有更好写的 (Theta(nsqrt n)) 算法,考虑暴力跳 fail,每次跳 fail 当前串长度都会减少 1,由于空节点的的值事 -1,我们直接跳过去,由于长度不同的串最多有 (sqrt n) 个,所以复杂度正确。

    const int N = 600050;
    int ch[N][26], en[N], f[N], id[N], ed[N], cnt = 1;
    char s[N];
    inline void insert(char *s, int k) {
    	int p = 1, len = strlen(s + 1); 
    	for (int i = 1;i <= len; i++) {
    		int c = s[i] - 'a';
    		if (!ch[p][c]) ch[p][c] = ++cnt;
    		p = ch[p][c];
    	}
    	en[k] = p, ed[p] = k;
    }
    
    int dep[N], siz[N], son[N], Top[N], dfn[N], num;
    int h[N], ne[N<<1], to[N<<1], tot;
    inline void add(int x, int y) { ne[++tot] = h[x], to[h[x] = tot] = y; }
    void dfs(int x) {
    	dep[x] = dep[f[x]] + (siz[x] = 1);
    	for (int i = h[x], y; i; i = ne[i]) {
    		dfs(y = to[i]), siz[x] += siz[y];
    		if (siz[son[x]] < siz[y]) son[x] = y;
    	}
    }
    
    void dfs2(int x, int topf) {
    	Top[x] = topf, dfn[x] = ++num, id[num] = x;
    	if (son[x]) dfs2(son[x], topf);
    	for (int i = h[x], y; i; i = ne[i])
    		if ((y = to[i]) != son[x]) dfs2(y, y);
    }
    
    void build(void) {
        queue<int> q;
        for (int i = 0;i < 26; i++)
            if (ch[1][i]) q.push(ch[1][i]), f[ch[1][i]] = 1;
            else ch[1][i] = 1;
        while (q.size()) {
            int x = q.front(); q.pop();
            if (x != 1) add(f[x], x);
            for (int i = 0;i < 26; i++) {
                if (!ch[x][i]) ch[x][i] = ch[f[x]][i];
                else q.push(ch[x][i]), f[ch[x][i]] = ch[f[x]][i];
            }
        }
    }
    
    #define ls p << 1
    #define rs ls | 1
    int mx[N<<2];
    
    void build(int p, int l, int r) {
    	mx[p] = -1;
    	if (l == r) return mx[p] = ed[id[l]] ? 0 : -1, void();
    	int mid = (l + r) >> 1;
    	build(ls, l, mid), build(rs, mid + 1, r);
    	mx[p] = max(mx[ls], mx[rs]);
    }
    
    void change(int p, int l, int r, int x, int c) {
    	if (l == r) return mx[p] = c, void();
    	int mid = (l + r) >> 1;
    	if (x <= mid) change(ls, l, mid, x, c);
    	else change(rs, mid + 1, r, x, c);
    	mx[p] = max(mx[ls], mx[rs]);
    }
    
    void query(int p, int l, int r, int L, int R, int &ans) {
    	if (L <= l && r <= R) return Mx(ans, mx[p]);
    	int mid = (l + r) >> 1;
    	if (L <= mid) query(ls, l, mid, L, R, ans);
    	if (R > mid) query(rs, mid + 1, r, L, R, ans);
    }
    
    void query(int x, int &ans) {
    	while (x) {
    		query(1, 1, num, dfn[Top[x]], dfn[x], ans);
    		x = f[Top[x]];
    	}
    }
    
    struct Heap {
    	priority_queue<int> A, B;
    	void update(void) { while (B.size() && A.top() == B.top()) A.pop(), B.pop(); }
    	int Top(void) { update(); return A.top(); }
    	void del(int x) { B.push(x); }
    	void push(int x) { A.push(x); }
    }q[300005];
    
    int pre[N], n, m;
    int main() {
    	read(n), read(m);
    	for (int i = 1;i <= n; i++) 
    		scanf ("%s", s + 1), insert(s, i), q[en[i]].push(0);
    	build(), dfs(1), dfs2(1, 1), build(1, 1, num);
    	for (int i = 1, x, y;i <= m; i++) {
    		int op; read(op);
    		if (op == 1) {
    			read(x), read(y);
    			q[en[x]].push(y), q[en[x]].del(pre[x]), pre[x] = y;
    			change(1, 1, num, dfn[en[x]], q[en[x]].Top());
    		}
    		else {
    			scanf ("%s", s + 1);
    			int len = strlen(s + 1), nw = 1, ans = -1;
    			for (int i = 1;i <= len; i++) {
    				nw = ch[nw][s[i] - 'a'];
    				query(nw, ans);
    			}
    			write(ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    几款国产的安卓系统
    微软所有正版软件下载网站ITELLYOU
    微软所有正版软件下载网站ITELLYOU
    键盘大小写状态显示(Softswitch) v2.3汉化绿色版
    牛顿定律的一些思考
    查看接地有没有ok
    Adobe Audition CC 2018软件安装
    声音的掩蔽效应的一些思考
    声学测量的基本量
    The Mean of the Sample Mean|Standard Deviation of the Sample Mean|SE
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13890180.html
Copyright © 2020-2023  润新知