• RMI 2021【杂题】


    传送门:Day 1Day 2

    present

    将所有满足 \(x,y\in A\implies\gcd(x,y)\in A\)\(A\subset\mathbb N_+\)\(\sum_{a\in A}\omega^a\) 排序求第 \(k\) 小。

    \(T\le 5\)\(k\le 1.5\cdot 10^9\)

    solution

    猜测 \(m:=\max A\) 不会很大,将 \([m]\) 划分为奇数和偶数两部分,奇数对偶数的限制为只能选某个子集内的数,于是 mitm,求答案按位贪心即可,时间复杂度 \(\mathcal O(Tm2^{m/2})\)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N = 1 << 19, biao[] = {0,2,4,7,13,22,38,67,121,208,346,663,1067,2084,3650,5621,10187,20228,33960,67673,106919,167302,316644,632549,988585,1672754,3243116,5502723,9032101,18060326,26876518,53747047,97409341,162001788,320354230,488138971,761529731,1523024388};
    int T, k[5], _[38][38], mzk[N], sum[N];
    vector<int> ans[5];
    bitset<N> oke, okl;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> T;
    	for(int i = 0;i < T;++ i) cin >> k[i];
    	for(int i = 1;i < 38;++ i)
    		for(int j = 1;j < 38;++ j)
    			_[i-1][j-1] = __gcd(i, j);
    	for(int m = 1;m < 38;++ m){
    		bool flg = false;
    		for(int i = 0;i < T;++ i) flg |= k[i] >= biao[m-1] && k[i] < biao[m];
    		if(!flg) continue;
    		int md = m>>1, le = 1<<md, lo = 1<<m-md;
    		memset(mzk, 0, lo<<2);
    		oke.reset(); okl.reset();
    		for(int S = 0;S < le;++ S){
    			bool flg = true;
    			for(int i = 0;i < md && flg;++ i) if(S >> i & 1)
    				for(int j = i+1;j < md && flg;++ j)
    					if((S >> j & 1) && !(S >> _[i][j]-1 & 1))
    						flg = false;
    			if(flg) oke.set(S);
    		}
    		for(int S = 0;S < lo;++ S){
    			bool flg = true;
    			for(int i = 0;i < m-md && flg;++ i) if(S >> i & 1)
    				for(int j = i+1;j < m-md && flg;++ j)
    					if((S >> j & 1) && !(S >> (_[i<<1][j<<1]>>1) & 1))
    						flg = false;
    			if(!flg) continue;
    			okl.set(S);
    			for(int j = 0;j < md;++ j){
    				flg = true;
    				for(int i = 0;i < m-md && flg;++ i)
    					if((S >> i & 1) && !(S >> (_[i<<1][j]>>1) & 1))
    						flg = false;
    				if(flg) mzk[S] |= 1 << j;
    			}
    		}
    		auto calc = [&](int od0, int od1, int ev0, int ev1){
    			vector<int> tmp; tmp.clear();
    			for(int i = 0;i < md;++ i)
    				if(ev1 >> i & 1) tmp.push_back(i);
    			int L = tmp.size(), lim = 1<<L;
    			for(int i = 0;i < lim;++ i){
    				int S = 0;
    				for(int j = 0;j < L;++ j)
    					if(i >> j & 1) S |= 1 << tmp[j];
    				sum[i] = oke[ev0 | S];
    			}
    			for(int md = 1;md < lim;md <<= 1)
    				for(int i = 0;i < lim;i += md<<1)
    					for(int j = 0;j < md;++ j)
    						sum[i | j | md] += sum[i | j];
    			int res = 0;
    			for(int i =	od1;;i = i-1 & od1){
    				if(okl[od0 | i] && (mzk[od0 | i] & ev0) == ev0){
    					int hah = 0;
    					for(int j = 0;j < L;++ j)
    						if(mzk[od0 | i] >> tmp[j] & 1) hah |= 1 << j;
    					res += sum[hah];
    				}
    				if(!i) break;
    			}
    			return res;
    		};
    		for(int i = 0;i < T;++ i) if(k[i] >= biao[m-1] && k[i] < biao[m]){
    			int od0 = 0, od1 = lo-1, ev0 = 0, ev1 = le-1;
    			k[i] -= biao[m-1];
    			(m & 1 ? od0 : ev0) |= 1 << (m-1>>1);
    			(m & 1 ? od1 : ev1) &= ~(1 << (m-1>>1));
    			ans[i].push_back(m);
    			for(int j = m-1;j;-- j){
    				(j & 1 ? od1 : ev1) &= ~(1 << (j-1>>1));
    				int res = calc(od0, od1, ev0, ev1);
    				if(k[i] >= res){
    					k[i] -= res;
    					(j & 1 ? od0 : ev0) |= 1 << (j-1>>1);
    					ans[i].push_back(j);
    				}
    			}
    			reverse(ans[i].begin(), ans[i].end());
    			k[i] = 0;
    		}
    	}
    	for(int i = 0;i < T;++ i){
    		cout << ans[i].size();
    		for(int u : ans[i]) cout << ' ' << u;
    		cout << '\n';
    	}
    }
    

    WeirdTree

    给定长为 \(n\) 的整数序列 \(a_1,\cdots,a_n\)\(q\) 次询问形如:

    • 给定 \(l,r,k\)\(k\) 次”将最靠左的最大值减 \(1\)“;
    • 给定 \(i,x\),令 \(a_i:=x\)
    • 给定 \(l,r\),求 \(\sum_{i=l}^ra_i\)

    \(n,q\le 3\cdot 10^5\)\(x,k,a_i\le 10^9\),强制在线。

    solution

    Segbeats 板子。

    Paths

    给定 \(n\) 个点的树和正整数 \(k\),边带非负权,设 \(\text{path}(u,v)\) 表示 \(u\)\(v\) 简单路径的边集,对所有 \(r\in [n]\)\(\bigcup_{i=1}^k\text{path}(r,v_i)\) 的权值和的最大值,其中 \(v_1,\cdots,v_k\) 是任意树上的点。

    \(k,n\le 10^5\)\(w_i\le 10^9\)

    solution

    经典结论是贪心选 \(k\) 次使得答案增加最多的路径,暴力即得 \(\mathcal O(n^2\log n)\) 的做法。

    需要仔细观察,设 \(\text{val}(x)\) 表示对于叶子 \(x\),选择它时答案的增量;以 \(1\) 为根,设 \(d_x,u_x\) 分别表示 \(x\) 子树内/外距离 \(x\) 最远的叶子,则当 \(r=1\)\(\text{val}(x)\) 即为最深的祖先 \(v\) 使得 \(d_v\ne x\)(若没有则 \(v=r\))的 \(\text{dis}(x,v)\)

    再观察一下,根从 \(r\) 移向儿子 \(q\) 时只有 \(d_q\)\(u_q\)\(\text{val}\) 值会改变,所以支持单点修改、求全局前 \(k\) 大和即可,时间复杂度 \(\mathcal O(n\log n)\)

    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long LL;
    typedef pair<LL, int> pii;
    const int N = 300003;
    template<typename T>
    bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
    int n, k, cnt, hd[N], to[N], nxt[N], w[N], fa[N];
    void add(int a, int b, int c){to[++cnt] = b; nxt[cnt] = hd[a]; hd[a] = cnt; w[cnt] = c;}
    pii down[N], down2[N], up[N];
    LL val[N], ans[N];
    pii operator + (const pii &a, int b){return MP(a.fi + b, a.se);}
    void dfs1(int x){
    	down[x] = MP(0, x);
    	for(int i = hd[x];i;i = nxt[i]) if(to[i] != fa[x]){
    		fa[to[i]] = x; dfs1(to[i]);
    		pii tmp = down[to[i]] + w[i];
    		if(down[x] <= tmp){down2[x] = down[x]; down[x] = tmp;}
    		else chmax(down2[x], tmp);
    	}
    	for(int i = hd[x];i;i = nxt[i])
    		if(to[i] != fa[x] && down[x].se != down[to[i]].se)
    			val[down[to[i]].se] = down[to[i]].fi + w[i];
    }
    void dfs2(int x){
    	for(int i = hd[x];i;i = nxt[i]) if(to[i] != fa[x]){
    		up[to[i]] = max(up[x], down[x] == down[to[i]] + w[i] ? down2[x] : down[x]) + w[i];
    		dfs2(to[i]);
    	}
    }
    LL hah[N], tot;
    void dfs3(int x){
    	for(int i = hd[x];i;i = nxt[i]) if(to[i] != fa[x]){
    		hah[tot++] = val[down[to[i]].se] -= w[i];
    		hah[tot++] = val[up[to[i]].se] += w[i];
    		dfs3(to[i]);
    		val[down[to[i]].se] += w[i];
    		val[up[to[i]].se] -= w[i];
    	}
    }
    LL trs[N];
    int trc[N];
    void upd(LL s, int c){
    	int p = tot - (lower_bound(hah, hah + tot, s) - hah); s *= c;
    	while(p <= tot){trs[p] += s; trc[p] += c; p += p & -p;}
    }
    LL qry(){
    	int p = 0, now = k; LL sum = 0;
    	for(int i = 18;~i;-- i)
    		if((p | 1<<i) < tot && now >= trc[p | (1<<i)]){
    			now -= trc[p |= (1<<i)]; sum += trs[p];
    		}
    	return sum + hah[tot - p - 1] * now;
    }
    void dfs4(int x){
    	ans[x] = qry();
    	for(int i = hd[x];i;i = nxt[i]) if(to[i] != fa[x]){
    		upd(val[down[to[i]].se], -1);
    		upd(val[down[to[i]].se] -= w[i], 1);
    		upd(val[up[to[i]].se], -1);
    		upd(val[up[to[i]].se] += w[i], 1);
    		dfs4(to[i]);
    		upd(val[down[to[i]].se], -1);
    		upd(val[down[to[i]].se] += w[i], 1);
    		upd(val[up[to[i]].se], -1);
    		upd(val[up[to[i]].se] -= w[i], 1);
    	}
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> k;
    	for(int i = 1, a, b, c;i < n;++ i){
    		cin >> a >> b >> c;
    		add(a, b, c); add(b, a, c);
    	}
    	dfs1(1); val[down[1].se] = down[1].fi; dfs2(1);
    	for(int i = 1;i <= n;++ i) if(val[i]) hah[tot++] = val[i];
    	dfs3(1);
    	sort(hah, hah + tot);
    	tot = unique(hah, hah + tot) - hah;
    	for(int i = 1;i <= n;++ i) if(val[i]) upd(val[i], 1);
    	dfs4(1);
    	for(int i = 1;i <= n;++ i) printf("%lld\n", ans[i]);
    }
    

    Gardening

    给定正整数 \(n,m,k\),给 \(n\times m\) 的网格图染 \(k\) 种颜色使得每种颜色都出现过且导出子图是简单环。需判断无解。

    \(\sum nm\le 2\cdot 10^5\)

    solution

    形如一堆矩形套起来,分类讨论即可。不妨设 \(n\le m\) 则有解的条件是 \(2\mid n,m\)\(m/2\le k\le nm/4\)\(k\ne nm/4-1\)\(n=m\implies k\ne n/2+1\)

    Speedrun

    这是一道单向通信+交互题

    • 给定 \(n\) 个点的树,对每个点 \(x\) 输出长为 \(20\)\(\texttt{01}\)\(a_x\)
    • 给定正整数 \(n\) 和当前位置 \(x\),你可以调用下述函数若干次,使得遍历每个点至少一次,且 \(\texttt{goTo}\) 返回 \(\texttt{false}\) 的次数不超过 \(2000\)
      • \(\texttt{bool goTo(int y)}\),当 \(x\)\(y\) 相邻时返回 \(\texttt{true}\) 并令 \(x:=y\),否则返回 \(\texttt{false}\)
      • \(\texttt{bool getHint(int y)}\),返回 \(a_{x,y}\)

    \(n\le 1000\)

    solution

    记录父亲和 DFS 序下一个的编号。

  • 相关阅读:
    【重点推荐】五美凡生论
    语言哲学宣言2018
    四要同环图
    知识分子必须毫不留情反对一切“教养阶层”
    世界上任何一件事的五个模块
    Web 在线制表工具稳定吗?和桌面报表工具对比哪个好用?
    Web 在线制表工具稳定吗?和桌面报表工具对比哪个好用?
    有没有简单易用的数据挖掘工具?
    BI、OLAP、多维分析、CUBE 这几个词是什么关系?
    传说中的中国复杂报表都长什么样?有什么特点?
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/16046656.html
Copyright © 2020-2023  润新知