首页 > 其他分享 >盖世计划--0731--AB班模拟

盖世计划--0731--AB班模拟

时间:2024-08-02 20:50:05浏览次数:17  
标签:std AB 0731 -- long i64 int define mod

今天的题不算难,但是没做出一题,有点失败。

A

你打完表之后发现并没有什么出色的性质。只能考虑爆搜。

代码好写,但是你要分析复杂度

最关键的一点是每一次递归至少多一个 \(1\),而 \(1\) 可以直接 return,所以最多递归 \(m\) 次就够了。


#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
/*

*/
i64 x, k, m, ans;
std::vector<i64> v;
void dfs(i64 now, i64 l) {
	if(!m) return;
	if(now == 1 || !l) {
		ans += now;
		m--;
		return;
	}
	for(i64 c : v) {
		if(c > now) break;
		if(!(now % c)) dfs(c, l - 1);
		if(!m) return;
	}
}
int main() {
	freopen("trans.in", "r", stdin);
	freopen("trans.out", "w", stdout);
	
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	std::cin >> x >> k >> m;

	if(k >= m) {
		std::cout << m << "\n";
		return 0;
	}
	for(i64 i = 1; i * i <= x; i++) {
		if(!(x % i)) {
			v.pb(i);
			if(x / i != i) v.pb(x / i);
		}
	}
	std::sort(v.begin(), v.end());

	k = std::min(k, m);
	dfs(x, k);

	std::cout << ans << "\n";

	return 0;
}

B

显然除了关键的 \(\log n\) 个点其他位置等价,可以组合数计算。假如最终函数停止时左边的关键点有 \(L\) 个,右边有 \(R\) 个,停止时是否找到 \(x\) 标记为 \(E\)。那么对一个三元组 \((L,R,E)\),考虑一个 \(y<x\) 的贡献:

\[yL{x-2\choose L-1}{n-x\choose R}(L-1)!R!(n-L-R-E)! \]

\(y> x\) 与 \(y=x\) 类似。

可以发现三元组与 \(x\) 无关,考虑一次 dfs 预处理出所有三元组,每次询问枚举每个三元组求出每个的答案即可。

复杂度 \(O(n\log n+q\log^2n)\)。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
/*

*/
const int N = 3e5 + 10, mod = 1e9 + 7, inv2 = (mod + 1) / 2;
i64 n, q;
std::map<std::array<i64, 3>, i64> mp;
i64 fac[N], inv[N], ans;
void dfs(i64 l, i64 r, i64 ls, i64 rs) {
	if(l > r) {
		mp[{ls, rs, 0}]++;
		return;
	}
	mp[{ls, rs, 1}]++;
	int mid = (l + r) >> 1;
	dfs(l, mid - 1, ls, rs + 1), dfs(mid + 1, r, ls + 1, rs);
}
i64 qpow(i64 a, i64 b) {
	i64 ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ret;
}
void init() {
	fac[0] = 1;
	for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod;
	inv[n] = qpow(fac[n], mod - 2);
	for(int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
i64 C(i64 n, i64 m) {
	if(m > n) return 0;
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
i64 sum(i64 l, i64 r) {
	return (l + r) * (r - l + 1) % mod * inv2 % mod;
}
int main() {
	freopen("binary.in", "r", stdin);
	freopen("binary.out", "w", stdout);

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	std::cin >> n >> q;

	dfs(1, n, 0, 0);
	init();

	while(q--) {
		i64 x;
		std::cin >> x;

		ans = 0;
		for(auto c : mp) {
			i64 L = c.fi[0], R = c.fi[1], E = c.fi[2], cnt = c.se;
			if(L) ans = (ans + cnt % mod * sum(1, x - 1) % mod * L % mod * C(x - 2, L - 1) % mod * C(n - x, R) % mod * fac[L - 1] % mod * fac[R] % mod * fac[n - L - R - E] % mod) % mod;
			if(R) ans = (ans + cnt % mod * sum(x + 1, n) % mod * R % mod * C(n - x - 1, R - 1) % mod * C(x - 1, L) % mod * fac[R - 1] % mod * fac[L] % mod * fac[n - L - R - E] % mod) % mod;
			if(E) ans = (ans + cnt % mod * x % mod * C(x - 1, L) % mod * fac[L] % mod * C(n - x, R) % mod * fac[R] % mod * fac[n - L - R - E] % mod) % mod; 
		}

		std::cout << ans << "\n";
	}

	return 0;
}

C

显然的做法,每个操作看成一条边,那么在一个连通块内的点内部一定能够排序成从小到大的形态,所有连通块拼起来就是最小字典序。问题出在边数是 \(O(n^2)\) 的。考虑优化建边。

我们不关心边是什么,我们只关心连通性,观察到值域只有 \(2^{20}\),考虑在值域上建边。

每个操作可以看成连向他的补集,然后补集连向他所有的子集。这样建图在新图上无向边的连通块就变成了强连通分量,跑一遍 tarjan 输出答案即可。

复杂度 \(O(n\log n)\)。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
/*

*/
const int N = 2e6 + 10;
int n;
int a[N];
int dfn[N], low[N];
int ins[N];
int st[N];
int bel[N];
int cnt[N];
int vis[N];
int pos[N];
std::vector<int> e[N], ans[N];
std::vector<pii> g[N];
int top, idx, tot;
void tarjan(int u) {
	st[++top] = u, ins[u] = 1;
	dfn[u] = low[u] = ++tot;
	for(int v : e[u]) {
		if(!dfn[v]) {
			tarjan(v);
			low[u] = std::min(low[u], low[v]);
		} else if(ins[v]) {
			low[u] = std::min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]) {
		++idx;
		int v;
		do {
			v = st[top--];
			if(cnt[v]) {
				g[idx].pb({v, cnt[v]});
			}
			bel[v] = idx;
			ins[v] = 0;
		} while(v != u);
	}
}
int main() {
	freopen("seq.in", "r", stdin);
	freopen("seq.out", "w", stdout);
	
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	std::cin >> n;

	int lim = (1 << 20) - 1;
	for(int i = 1; i <= n; i++) {
		std::cin >> a[i];
		cnt[a[i]]++;
		e[a[i]].pb(lim ^ a[i]);
	}

	for(int i = 1; i <= lim; i++) {
		for(int j = 0; j < 20; j++) {
			if((i >> j) & 1) {
				e[i].pb(i ^ (1 << j));
			}
		}
	}

	for(int i = 0; i <= lim; i++) {
		if(!dfn[i]) tarjan(i);
	}

	for(int i = 1; i <= idx; i++) {
		if(!g[i].size()) continue;
		std::sort(g[i].begin(), g[i].end());
		for(int j = 0; j < g[i].size(); j++) {
			for(int k = 1; k <= g[i][j].se; k++) ans[i].pb(g[i][j].fi);
		}
	}

	for(int i = 1; i <= n; i++) {
		std::cout << ans[bel[a[i]]][pos[bel[a[i]]]++] << " ";
	}
	std::cout << "\n";

	return 0;
}

D

简单的是 \(O(n^2\log n)\) 的暴力,枚举两个点计算答案。但这是没有前途的。

考虑枚举颜色,把式子写出来。

\[\sum\limits_{c}\sum\limits_{c\in[l_i,r_i]}\sum\limits_{c\in[l_j,r_j]}\frac{K}{k_ik_j}(d_i+d_j-2d_{lca(i,j)}) \]

把 \(K\) 提出,然后整理好。

\[\sum\limits_{c}K\sum\limits_{c\in[l_i,r_i]}\sum\limits_{c\in[l_j,r_j]}(\frac{d_i}{k_ik_j}+\frac{d_j}{k_ik_j})-\frac{2d_{lca(i,j)}}{k_ik_j} \]

考虑前面括号的部分的处理,实际上可以写成:

\[\frac{d_i}{k_i}\cdot\frac{1}{k_j}+\frac{d_j}{k_j}\cdot\frac{1}{k_i} \]

如果设 \(s_0=\sum\frac{d_i}{k_i}\),\(s1=\sum\frac{1}{k_i}\),那么 \(s_0\cdot s_1\) 基本为上式(只不过要减去 \(i=j\) 的部分),所以从小到大枚举 \(c\) 的时候扫描线,维护这两个值即可。

\(lca\) 的部分用上经典的 trick,将式子拆成:\(\frac{2d_{lca(i,j)}}{k_i}\cdot\frac{1}{k_j}\)。前者直接作为 \(i\) 到根的路径贡献到每一条边。当插入 新的点 \(j\) 时,查询 \(j\) 到根的路径上的和再乘上 \(\frac{1}{k_j}\) 即为贡献,这部分可以树剖+线段树维护区间和。

复杂度 \(O(n\log n)\)。

#include <bits/stdc++.h>
#define pii std::pair<i64, i64>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
/*

*/
const int N = 1e5 + 10, mod = 1e9 + 7;
i64 ans, K = 1;
int n, idx, maxn;
int l[N], r[N];
int id[N];
int top[N];
int sz[N];
int fa[N];
int len[N];
i64 inv[N];
int son[N];
i64 dep[N];
std::vector<pii> v[N]; 
std::vector<int> e[N];
i64 qpow(i64 a, i64 b) {
	i64 ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ret;
}
void dfs1(int u, int f) {
	dep[u] = dep[f] + 1;
	fa[u] = f, sz[u] = 1;
	for(auto v : e[u]) {
		if(v == f) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if(sz[son[u]] < sz[v]) son[u] = v;  
	}
}
void dfs2(int u, int topf) {
	id[u] = ++idx;
	top[u] = topf;
	if(!son[u]) return;
	dfs2(son[u], topf);
	for(auto v : e[u]) {
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}
struct seg {
	i64 v, tg;
} t[N << 2];
void pushup(int u) {t[u].v = (t[u << 1].v + t[u << 1 | 1].v + mod) % mod;}
void mdf(seg &u, i64 v, int l, int r) {
	u.v = (u.v + (r - l + 1) * v % mod) % mod;
	u.tg = (u.tg + v) % mod;
}
void pd(int u, int l, int r) {
	if(!t[u].tg) return;
	int mid = (l + r) >> 1;
	mdf(t[u << 1], t[u].tg, l, mid);
	mdf(t[u << 1 | 1], t[u].tg, mid + 1, r);
	t[u].tg = 0;
}
i64 ask(int u, int l, int r, int L, int R) {
	if(L <= l && r <= R) {
		return t[u].v;
	}
	int mid = (l + r) >> 1; pd(u, l, r);
	i64 ret = 0;
	if(L <= mid) ret = (ret + ask(u << 1, l, mid, L, R) + mod) % mod;
	if(R > mid) ret = (ret + ask(u << 1 | 1, mid + 1, r, L, R) + mod) % mod;
	return ret; 
}
void add(int u, int l, int r, int L, int R, i64 x) {
	if(L <= l && r <= R) {
		mdf(t[u], x, l, r);
		return;
	}
	int mid = (l + r) >> 1; pd(u, l, r);
	if(L <= mid) add(u << 1, l, mid, L, R, x);
	if(R > mid) add(u << 1 | 1, mid + 1, r, L, R, x);
	pushup(u);
}
void upd(int u, int v) {
	while(u) {
		add(1, 1, n, id[top[u]], id[u], v);
		u = fa[top[u]];
	}
}
i64 qry(int u) {
	i64 ret = 0;
	while(u) {
		ret = (ret + ask(1, 1, n, id[top[u]], id[u]) + mod) % mod;
		u = fa[top[u]];
	}	
	return ret;
}
int main() {
	freopen("route.in", "r", stdin);
	freopen("route.out", "w", stdout);
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	std::cin >> n;

	for(int i = 1; i <= n; i++) {
		std::cin >> l[i] >> r[i];
		v[l[i]].pb({i, 1});
		v[r[i] + 1].pb({i, -1});
		len[i] = r[i] - l[i] + 1;
		inv[i] = qpow(len[i], mod - 2);
		K = K * len[i] % mod; 
		maxn = std::max(maxn, r[i]);
	}

	for(int i = 1; i < n; i++) {
		int u, v;
		std::cin >> u >> v;
		e[u].pb(v), e[v].pb(u);
	}

	dfs1(1, 0), dfs2(1, 1);

	i64 s0 = 0, s1 = 0, s2 = 0, s3 = 0;
	for(int i = 1; i <= maxn; i++) {
		for(auto x : v[i]) {
			i64 c = x.fi;
			if(x.se == -1) {
				s0 = (s0 - (dep[c] * inv[c] % mod + mod) % mod) % mod;
				s1 = (s1 - inv[c] + mod) % mod;
				s2 = (s2 - (dep[c] * inv[c] % mod * inv[c] % mod + mod) % mod) % mod;
				upd(c, mod - inv[c]);
				s3 = (s3 - inv[c] * qry(c) % mod + mod) % mod;
			} else {
				s0 = (s0 + dep[c] * inv[c] % mod + mod) % mod;
				s1 = (s1 + inv[c] % mod) % mod;
				s2 = (s2 + dep[c] % mod * inv[c] % mod * inv[c] % mod) % mod;
				s3 = (s3 + inv[c] * qry(c) % mod) % mod;
				upd(c, inv[c]);
			}
		}
		ans = (ans + K * (((s0 * s1 % mod) - s2 + mod) % mod - 2ll * s3 + 2ll * mod) % mod) % mod;
	}

	std::cout << ans << "\n";

	return 0;
}

标签:std,AB,0731,--,long,i64,int,define,mod
From: https://www.cnblogs.com/FireRaku/p/18339586

相关文章

  • vs2015卸载和安装
    vs2015卸载和安装0.摘要可能对大家有帮助的地方: a.vs2015卸载和安装的流程; b.安装时的error:“teamexplorerformicrosoftvisualstudio2015update3ctp1error”解决方式; c.vs2015社区版的下载地址;如果这三点不能解决你遇到的问题,就没必要往下看了。1.卸载......
  • 《大道至简》读后感悟
    最近几天我阅读了一本经典软件工程读物《大道至简————软件工程实践者的思想》,其作者为周爱民。读完之后我从中有所感受,思考其中所说的内容对照自身去学习改进。全书都在引用中国古代故事“愚公移山”和各种中国古代的经典书籍的句子,很是通俗易懂。贯穿全书的可以说是愚公移山......
  • Android开发 - BrowseFragment 类解析
    BrowseFragment是什么例如电视应用屏幕上有很多行,每行显示一组视频,比如“热门电影”、“新剧集”、“推荐给你”等。每行可以左右滚动,显示不同的视频缩略图。BrowseFragment就是用来创建这种界面的主要功能每行有一个标题:告诉你这行内容是什么,比如“热门电影”每行可以滚......
  • CSP13
    T1本来是道状压签到题,看成博弈论了,其实是不对的,为什么不对,建图时是存在环的情况的,所以不能建一棵树后跑\(sg\)函数所以根据数据范围,我们可以状压,这就很简单了,每一次继承的状态为子状态相反的状态(不要试图只表示赢得状态)考试代码(41,43)pts#include<bits/stdc++.h>#defi......
  • COSC2391 Further Programming
    COSC2391 FurtherProgramming/COSC1295AdvancedProgrammingAssignment 1–Semester2 2024IntroductionYouarerequiredtoimplementabasicJavaprogram usingJava.This assignment is designed to:•   TestyourknowledgeofbasicJava concepts......
  • 对于泛型和类型转换的优先级
    你们猜猜谁先打印,不看答案,能猜出来吗,写在评论区下面有3道题目,分别写出答案在评论区1、classTest{publicstaticvoidMain(){Foo("Hello");}publicstaticvoidFoo(objectx){Console.WriteLine("object");......
  • CIFAR-10 Implementing a Convolutional Neural Network
    Coding Assignment 4: Implementing aConvolutional Neural Network for CIFAR-10using KerasJuly 28, 20241 OverviewInthisassignment,youwillimplement a Convolutional Neural Network (CNN) to classify images from the CIFAR-10 dataset......
  • 从零开始学逆向CTF比赛,免费参加,欢迎来玩!
    大家好,我是轩辕。告诉大家一个好消息:我准备了一次逆向CTF比赛,面向所有人开放,无需购买课程,优秀的小伙伴还有奖励,参赛方式在文末会介绍,欢迎大家一起来玩。举办这次CTF比赛,是为了检验大家从零开始学逆向的学习成果。就在不久前,我的这套视频课程终于完结了。不过要友情提醒一下,......
  • VirtualBox扩容CentOS-7虚拟机磁盘
    1、背景描述如上图所示,根路径“/”所在的文件系统已没有可用的磁盘空间,需要扩容磁盘。df-h2、VirtualBox操作2.1、查看当前虚拟磁盘的大小如上图所示,点击打开选中的虚拟机的Settings界面。如上图所示,当前虚拟机的虚拟磁盘大小为8GB。2.2、修改虚拟磁盘的大小如......
  • 1990-2022年 上市公司-战略差异度(原始数据、计算代码、参考文献和最终计算结果)
    上市公司战略差异度是衡量企业在战略制定和实施过程中所展现的独特性和创新性的指标。它体现了公司对市场环境、行业趋势及自身能力的独特见解和战略布局。通过分析上市公司的战略差异度,可以深入理解企业的市场竞争策略、行业定位和发展方向。战略差异度的重要性市场竞争力:战......