首页 > 其他分享 >test2024.3.21

test2024.3.21

时间:2024-03-27 11:56:08浏览次数:19  
标签:cnt return 21 int 平台 dep Go test2024.3

多边形

题意:

有一个长度为 \(n\) 的 \(0/1\) 序列,有 \(m\) 次操作 \(u_{i},v_{i}\),若 \(a_{u_{i}}=1,a_{v_{i}}=0\) 则交换。

询问对于 \(1,2,\dots,n\) 中的每个 \(k\),有多少种初始状态,满足恰好有 \(k\) 个 \(1\),并且经过 \(m\) 次操作后,所有 \(1\) 形成了一个区间。答案对 \(2\) 取模。

\(n \le 35,m \le 1000\)。

分析:

显然要搜索。

对于每个位置用 \(0 /1 /2\) 记录,分别表示确定为 \(0\)、确定为 \(1\)、没确定。

对于一个操作 \(u,v\),简单分讨一下:

  • \(u=v=2\),若 \(u \ne v\),则操作后一定为 \(0,1\),这样的有两种情况,因此不用处理。若 \(u=v\),则会产生 \(1,1\) 和 \(0,0\) 两个分支。
  • \(u,v\) 恰好有一个为 \(2\)。
  • \(u,v\) 没有 \(2\)。

搜完 \(m\) 次操作后随便处理一下。时间复杂度为 \(O(2^{\frac{n}{2}} n^2)\) 或 \(O(2^{\frac{n}{2}} n)\),事实上完全跑不满。

代码:
#include<bits/stdc++.h>
#define int long long
#define N 1010
using namespace std;
int n, m;
int U[N], V[N], now[N], ans[N];
void dfs(int dep) {
	if(dep == m + 1) {
		//for(int i = 1; i <= n; i++) cout << now[i] << " ";
		//cout << endl;
		int L = 0;
		for(int i = 1; i <= n; i++)
			if(now[i] == 1) {
				L = i;
				break;
			}
		if(L == 0) {
			for(int Pos = 1; Pos <= n; ) {
				if(!now[Pos]) {
					Pos++;
					continue;
				}
				int R = Pos - 1;
				while(now[R + 1] == 2 && R < n) R++;
				for(int u = Pos; u <= R; u++)
				for(int v = u; v <= R; v++) ans[v - u + 1]++;
				Pos = R + 1;
			}
			return;
		}
		int R = L;
		for(int i = L + 1; i <= n; i++) {
			if(now[i] == 0) break;
			if(now[i] == 1) R = i;
		}
			
			
		for(int i = R + 1; i <= n; i++)	
			if(now[i] == 1) return;
		//[L, R]
		int l = L, r = R;
		while(now[l] != 0 && l > 0) l--;
		while(now[r] != 0 && r <= n) r++;
		l++; r--;
		//cout << l << " , " << L << "   " << R << " , " << r << endl;
		for(int u = l; u <= L; u++)
		for(int v = R; v <= r; v++) ans[v - u + 1]++;
		return;
	}
	int u = now[U[dep]], v = now[V[dep]];
	if(u == 2 && v == 2) {
		now[U[dep]] = 1;
		now[V[dep]] = 1;
		dfs(dep + 1);
		now[U[dep]] = 0;
		now[V[dep]] = 0;
		dfs(dep + 1);
		now[U[dep]] = 2;
		now[V[dep]] = 2;
	}
	else if(u == 2 || v == 2) {
		if(u == 1 && v == 2) {
			swap(now[U[dep]], now[V[dep]]);
			dfs(dep + 1);
			swap(now[U[dep]], now[V[dep]]);
		}
		else if(u == 2 && v == 1) {
			dfs(dep + 1);
		}
		else if(u == 2 && v == 0) {
			swap(now[U[dep]], now[V[dep]]);
			dfs(dep + 1);
			swap(now[U[dep]], now[V[dep]]);
		}
		else if(u == 0 && v == 2) {
			dfs(dep + 1);
		}
	}
	else {
		if(u == 1 && v == 0) swap(now[U[dep]], now[V[dep]]);
		dfs(dep + 1);
		if(u == 1 && v == 0) swap(now[U[dep]], now[V[dep]]);
	}
}
signed main() {
	cin >> n >> m;
	for(int i = 1; i <= m; i++) cin >> U[i] >> V[i];
	for(int i = 1; i <= n; i++) now[i] = 2;
	dfs(1);
	for(int i = 1; i <= n; i++) cout << ans[i] % 2 << " ";
	return 0;
}

倒水

题意:

分析:

记 \(cnt_{i}\) 表示能到达 \(i\) 的平台的个数(包括本身),那么答案显然为 \(\sum_{i=1}^{n} \frac{1}{cnt_{i}}\)。因为 \(cnt_{i}\) 个数随意排列,\(i\) 在最后一个位置的概率为 \(\frac{cnt_{i}}{1}\)。

考虑计算 \(cnt\):对于平台 \(u\) 而言,高度从低往高更新,如果 \(v\) 与 \(u\) 有交且不是 \(v\) 包含 \(u\),那么 \(u \leftarrow u \cup v\)。最后 \(cnt\) 就是被 \(u\) 覆盖的区间。

记 \(L2_{i},R2_{i}\) 分别表示覆盖 \(i\) 的左右端点的在 \(i\) 平台上面的高度最低的平台。

如何找天花板呢?记 \(L1_{i},R1_{i}\) 分别表示 \(i\) 平台的左右端点能覆盖到的在 \(i\) 下面高度最高的平台。

再记一个 \(Go_{i}\) 表示 \(i\) 能跳到最高的平台,那么 \(i\) 从大到小枚举,\(Go_{L1_{i}} \leftarrow Go_{i},Go_{R1_{i}} \leftarrow Go_{i}\)。

\(Go_{i}\) 通过 \(L2_{i}\) 往上跳一步就是平台。

知道了平台的高度就可以很套路地使用倍增计算这个图形所围成的平台的个数。

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

代码:
#include<bits/stdc++.h>
#define int long long
#define N 1000005
#define mod 1000000007
using namespace std;
int n;
int Pow(int a, int n) {
	if(n == 0) return 1;
	if(n == 1) return a;
	int x = Pow(a, n / 2);
	if(n % 2 == 0) return x * x % mod;
	else return x * x % mod * a % mod;
}
int inv(int x) {
	return Pow(x, mod - 2);
}
int c[N * 4], tag[N * 4];
void maketag(int u, int x) {
	c[u] = x;
	tag[u] = x;
}
void pushdown(int u) {
	if(!tag[u]) return;
	maketag(u * 2, tag[u]);
	maketag(u * 2 + 1, tag[u]);
	tag[u] = 0;
}
void update(int u, int L, int R, int l, int r, int x) {
	if(R < l || r < L) return;
	if(l <= L && R <= r) {
		maketag(u, x);
		return;
	}
	int mid = (L + R) / 2;
	pushdown(u);
	update(u * 2, L, mid, l, r, x);
	update(u * 2 + 1, mid + 1, R, l, r, x);
}
int query(int u, int L, int R, int x) {
	if(L == R) return c[u];
	int mid = (L + R) / 2;
	pushdown(u);
	if(x <= mid) return query(u * 2, L, mid, x);
	else return query(u * 2 + 1, mid + 1, R, x);
}
int t[N];
int lowbit(int x) {
	return x & (-x);
}
void add(int x, int y) {
	for(int i = x; i <= 2 * n; i += lowbit(i)) 
		t[i] += y;
}
int query(int x) {
	int res = 0;
	for(int i = x; i; i -= lowbit(i))
		res += t[i];
	return res;
}
int ask(int L, int R) {
	if(L > R) return 0;
	return query(R) - query(L - 1);
}
int ans, l[N], r[N], Go[N]; //Go[i]表示i最高跳到的平台
int L1[N], R1[N]; //表示i能直接流到的高度最大的平台
int L2[N], R2[N]; //表示i头上与它有交集的高度最低的平台
int L[N][22], R[N][22], SL[N][22], SR[N][22];
struct node {
	int ll, rr, h;
}a[N];
bool cmp(node x, node y) {
	return x.rr < y.rr;
}
bool cmp2(node x, node y) {
	return x.ll < y.ll;
}
void init() {
	for(int i = 1; i <= n; i++) {
		L1[i] = query(1, 1, 2 * n, l[i]);
		R1[i] = query(1, 1, 2 * n, r[i]);
		update(1, 1, 2 * n, l[i], r[i], i);
	}
	for(int i = n; i >= 1; i--) {
		Go[L1[i]] = max(Go[L1[i]], Go[i]);
		Go[R1[i]] = max(Go[R1[i]], Go[i]);			
	}
	update(1, 1, 2 * n, 1, 2 * n, n + 1);
	for(int i = n; i >= 1; i--) {
		L[i][0] = L2[i] = query(1, 1, 2 * n, l[i]);
		R[i][0] = R2[i] = query(1, 1, 2 * n, r[i]);
		update(1, 1, 2 * n, l[i], r[i], i);
		//cout << i << " : " << L[i][0] << " , " << R[i][0] << endl;
	}
	sort(a + 1, a + n + 1, cmp);
	for(int i = 1; i <= n; i++) {
		//cout << a[i].h << endl;
		add(a[i].h, 1);
		SR[a[i].h][0] = ask(a[i].h, R[a[i].h][0]);
	}
	
	sort(a + 1, a + n + 1, cmp2);
	memset(t, 0, sizeof(t));
	for(int i = 1; i <= n; i++) {
		add(a[i].h, 1);
		SL[a[i].h][0] = ask(a[i].h + 1, L[a[i].h][0] - 1);
	}
	//for(int i = 1; i <= n; i++) cout << i << " : " << SL[i][0] << endl;
}
signed main() {
	//freopen("ex_water3.in", "r", stdin);
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> l[i] >> r[i];
		Go[i] = i;
		a[i].ll = l[i];
		a[i].rr = r[i];
		a[i].h = i;
	} 
	init();
	for(int j = 1; j <= 20; j++) {
		for(int i = 1; i <= n; i++) {
			L[i][j] = L[L[i][j - 1]][j - 1];
			R[i][j] = R[R[i][j - 1]][j - 1];
			SL[i][j] = SL[i][j - 1] + SL[L[i][j - 1]][j - 1];
			SR[i][j] = SR[i][j - 1] + SR[R[i][j - 1]][j - 1];
		}
	}
	for(int i = 1; i <= n; i++) {
		int cnt = 0, x = i;
		for(int dep = 20; dep >= 0; dep--) {
			if(R[x][dep] != 0 && R[x][dep] <= L[Go[i]][0]) {
				cnt += SR[x][dep];
				x = R[x][dep];
			}
		}
		x = i;
		for(int dep = 20; dep >= 0; dep--) {
			if(L[x][dep] != 0 && L[x][dep] <= L[Go[i]][0]) {
				cnt -= SL[x][dep];
				x = L[x][dep];
			}
		}
		ans = (ans + inv(cnt)) % mod;
	}
	cout << ans;
	return 0;
}
/*
5
2 9
3 4
1 8
6 10
5 7
*/

标签:cnt,return,21,int,平台,dep,Go,test2024.3
From: https://www.cnblogs.com/xcs123/p/18098630

相关文章

  • COMP9021编程原理
    COMP9021编程原理2024年第1学期课业1价值13马克,第7周星期一上午10点到期1.一般事项1.1目标本任务的目的是:•培养解决问题的技能。•以中型Python程序的形式设计和实现问题的解决方案。•练习算术计算、测试、重复、列表和字符串的使用。•使用程序编程。1.2标记该课业价......
  • S-073N 3BHB009884R5211 高压电子元件 用于控制和调整信号的相位
    S-073N3BHB009884R5211高压电子元件是一款专为高压场合设计,用于控制和调整信号相位的电子元件。它集成了多种先进功能,能够满足复杂和精细的相位控制需求。在高压环境中,该电子元件能够实现精确的高压电机控制,从而提高系统的稳定性和效率。它内置的过载保护、短路保护、欠压保......
  • 华为数通方向HCIP-DataCom H12-821题库(多选题:181-200)
    第181题在BGP中Community属性为可选过渡属性,是一种路由标记,用于简化路由策略的执行。它分为自定义团体属性和公共团体属性,那么以下属于公共团体属性的是哪些项?A、No_Export_SubconfedB、No_AdvertiseC、No_ExportD、Internet【正确答案】ABCD【答案解析】第182......
  • P2155 [SDOI2008] 沙拉公主的困惑
    关于题目题目描述大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于数量可能非常大,你......
  • 卡码java基础课 | 21.图形的面积(面向对象)
    学习内容:面向对象的特性,封装、继承、多态。重点归纳:成员变量的定义:访问修饰符、数据类型、变量名。访问修饰符,private只能类内部使用,protected只能类内部和子类使用,public可以从任何地方访问。方法:访问修饰符、返回类型、方法名、参数列表。以及构造函数。1.封装:通过将属性设......
  • 洛谷题单指南-集合-P1621 集合
    原题链接:https://www.luogu.com.cn/problem/P1621题意解读:a~b之间的数,把有大于等于p的公共质因数的数进行合并作为一个集合,求一共有多少个集合。解题思路:要进行集合合并、统计集合数,可以使用并查集,有两种做法:1、暴力法80%的数据在1000范围内,因此通过双重循环枚举,判断两个数的......
  • 【知识点】JDK 8-21 新特性总结
    只列出主要新特性Java8Lambda表达式函数式接口StreamAPI新的日期和时间API默认方法Optional类Java9-11Java9模块化系统G1成为默认垃圾回收器(之前是CMS,ConcurrentMark-Sweep,即新生代+老年代标记清除。)String存储结构优化(之前内部是char[],现在是byte[],更......
  • 力扣刷题之21.合并两个有序链表
    仅做学习笔记之用。题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例1:输入:l1=[1,2,4],l2=[1,3,4]输出:[1,1,2,3,4,4]示例2:输入:l1=[],l2=[]输出:[]示例3:输入:l1=[],l2=[0]输出:[0]......
  • P1121 环状最大两段子段和
    原题链接题解这里和线性最大两段子段和不同,没有子段之间必须间隔一米,所以处理方式略有不同code#definelllonglong#include<bits/stdc++.h>usingnamespacestd;lla[200005]={0},pre[200005]={0},suf[200005]={0};intmain(){ios::sync_with_stdio(false);......
  • YC262A [ 20240321 CQYC省选模拟赛 T1 ] 多边形(polygon)
    题意有一个由\(0/1\)组成的字符串\(S\)。给你\(m\)次操作。假如\(S_{u}=1\)且\(S_{v}=0\),则交换\(S_{u},S_{v}\)。假如对于所有的\(S\),使得最终字符串\(S'\)的所有\(1\)相邻。请输出\(1\)的个数为\([1,n]\)的\(S\)的方案数。答案对\(2\)取模。......