首页 > 其他分享 >省常中游记

省常中游记

时间:2022-10-11 12:33:47浏览次数:39  
标签:输出 le 10 int 样例 格式 游记 省常中

Day 1

没有题解 全是数论 T1 类欧几里得 T2 积函数 T3 容斥原理 T4 仙人掌拆分

Day 2

上午纯坐牢

T1

题目描述

盒子里有 \(n\) 个球,球的颜色有黑白两种,但是不知道初始状态

一共进行 \(m\) 操作,每次会从盒子中取出一个球,然后放入黑白各一个球,然后再取出一个球

取出的 \(2m\)个球会形成一个序列,你需要对所有初始状态计算本质不同的序列对
\(p\) 取模的结果

两个序列不同当且仅当存在一个位置,其所代表的球的颜色在两个序列中不同

这里的初始状态指的是盒子中两种颜色的球的个数

输入格式

一行三个数 \(n, m, p\)

输出格式

一行一个数表示答案

样例输入

 1 2 114514

样例输出

 8

数据范围

$ 1 \le n, m \le 3 * 10^{3}, 1 \le p \le 10^{9}$

题解

Code

T2

题目描述

定义一个可重集 \(S\) 的众数 \(f(S)\) 为集合中出现次数最多且编号最小的数字。例如 \(f(1,2,2,3) = 2,f(2,2,3,3) = 2\)。

定义一个可重集 \(S\) 的价值为\(2^{f(S)}\) 。

现在你有一个长度为 \(n\) 的序列 \(a_{1},a_{2},...,a_{n}\),其中数字 \(a_{x}\) 表示可重集 \(S\) 中正整数 \(x\) 出现了 \(a_{x}\) 次。你需要将这个可重集 \(S\) 不重、不漏地划分成若干个可重集,使得这些可重集的价值之和最小。

你只需要输出这个数值在模 \(998244353\) 意义下的结果。

接下来,会有 \(q\) 次修改,每次修改会将 \(a_{x}\) 改为 \(y\) 。每次修改后你都要重新输出上面所描述的数值。

输入格式

第一行一个正整数 \(n\) ,表示序列的长度。

接下来一行 \(n\) 个正整数,分别表示$a_{1}, a_{2}, ..., a_{n} $。

接下来一个正整数 \(q\) ,表示修改次数。

接下来 \(q\) 行,每行两个正整数 \(x, y\),表示将 \(a_{x}\) 改为 \(y\)。

输出格式

答案对 \(9982444353\) 取模。

在修改之前,先输出一个数值表示答案。

每次修改之后,都要输出一个数值表示答案。

样例输入

 0
 4
 4 1 2 3 
 2
 1 1 
 1 2

样例输出

 2
 10
 6

数据范围

\(1 \le n \le 2 * 10^{5}, 0 \le q \le 2 * 10^{5}, 1 \le a_{i}, y \le 2 * 10^{5}, 1 \le x \le n\) 。

题解

Code

T3

题目描述

有一棵 \(n\) 个节点的树,一条树边可以记为 $(u_{i}, v_{i}, w_{i}),表示连接点 \(u_{i}\) 和点 \(v_{i}\) 权为 \(w_{i}\)。

对于边 \(i\) , \(a_{i,j}\) 的定义如下:令 \(c_{j,i}\) 为点 \(j\) 与其他 \(n - 1\) 个点之间的简单路径中经过边 \(i\) 的路径数,那么 \(a_{i,j} = c_{j,i} * w_{i}\) 。

一条边 \(i\) 在点 \(j\) 是优的,当且仅当不存在有另一条边 \(k\) 使得 \(a_{k,i} > a_{i,j}\)(可能有多条边在同一个点是优的)。

令 \(f(i)\) 表示边 \(i\) 在多少个点上是优的,现在要求 \(f(i)\) 。

输入格式

第一行,一个正整数 \(n\) 。

接下来 \(n - 1\) 行,每行三个正整数 \(u_{i}, v_{i}, w_{i}\) 表示一条边的信息。

输出格式

为减少输出量,共输出一行,一个整数,表示所有 \(f(i)\) 的异或和。

样例输入

 5
 1 2 3
 2 3 1
 3 4 1
 3 5 1

样例输出

 2

数据范围

\(n \le 10^{7}, w_{i} \le 10^{10}\)

题解

Code

T4

题目描述

GreenDuck 买到了最新的扫地机器人——RobotDuck。为了更高效地清扫房间,GreenDuck 决定分析一下房间的布局和 RobotDuck 的清扫机制。

GreenDuck 的房间可以看成是
行 列的网格,每个格子中要么是空的,要么放了一件家具。同时他惊奇地发现,每个家具都很薄(可以看成是一条线段),两个端点分别占据了一个格子的西北角和东南角!

RobotDuck 在清扫时会采取这样一种机制:刚开始,可以给它设定一个方向(向南或向东),接着它将一直沿着直线行进。如果碰到一个家具,那么会反弹。具体方式如下图所示。

GreenDuck 一开始得知,在自己的房间里有 \(k\) 件家具,第 \(i\) 件家具在第 \(x_{i}\)行,\(y_{i}\) 列。接下来,他会进行 \(Q\)次测试。

第一种测试,是在一个没有家具的格子上放上一件家具(方向保持一致)。这种测试后,他不会拿走任何家具。

第二种测试,是将 RobotDuck 贴着墙壁然后释放。具体来说,如果 RobotDuck 放在北面(对应了图中矩形的上边界),那么它会从第一行某个格子的上边界的中心出发,面向南面行进。如果 RobotDuck 放在西面(对应了图中矩形的左边界),那么它会从第一列某个格子的左边界的中心出发,面向东面行进。在行进过程中,它遵守清扫的机制。

GreenDuck 想知道,在每次第二种测试时,RobotDuck 在反弹恰好 \(q\) 次后会在哪个格子里。请你告诉他。

输入格式

第一行四个数字,\(type, n, m, k\), 分别表示数据类型(你可能不需要),行数,列数,一开始有的家具件数。

接下来 \(k\)行,每行两个整数\(x_{i}, y_{i}\),分别表示这件家具的行数和列数。

接下来一行一个整数 \(Q\) ,表示测试的次数。

接下来 \(Q\) 行,首先输入一个数字 \(w\)。

若 \(w\) 为 \(1\) ,则会有两个数字 \(x,y\),分别表示新添的家具的行数和;列数。

若 \(w\) 为 \(2\),则会有三个数字 \(x, y\)。若 \(x = 0\),表示RobotDuck 从第一行第 \(y\)列格子的上边界的中心面向南行进。否则 \(y = 0\),表示 RobotDuck 从第一列第 \(x\) 行格子的左边界的中心面向东行进。 \(q\) 表示反弹的次数。

输出格式

对于每个 \(w = 2\) 的操作,输出一行两个数字 \(x\) 和 \(y\)分别表示所在格子的行数和列数。

特别地,若 RobotDuck 在第 \(q\) 次反弹之前就碰到了墙壁,若墙壁是第 \(n\) 行格子的下边界,输出" \(n + 1\)列数",否则输出"行数 $ m + 1$ "。

样例输入

 0 4 4 1
 2 2
 5
 2 2 0 3
 1 3 2
 2 2 0 2
 2 2 0 3
 2 2 0 4

样例输出

 5 2
 3 2
 3 5
 3 5

样例解释

数据范围

对于所有数据,家具的坐标不会重复,每次第二种操作要么 \(x=0\) 要么 \(y=0\)。 \(1 \le q \le 200000\)。

题解

对于每一个格子来说建立两个点,分为上半部分和下半部分。然后分别对外连边。于是每一次查询就是相当于查询弹了 \(q\) 次后所到达的地方。
在这里的路径要记录弹了的次数。方便之后的查询。
关于加家具的操作可以考虑上面所说的上下两部分, 然后交换连一下, 还是很好处理的。
本来一个点的 上半部分由别人上部分向右连的, 加了家具之后就是从别人的下部分向下连, 另外半边也是一样。
涉及到单点交换修改, 且每一条路径都是链的情况下我们可以考虑使用链表经行处理。
不过要么修改时间复杂度高达 $ O(n) $, 要么查询的时间复杂度高达 $ O(n) $
于是考虑分块, 再结合基本不等式可以得出最优的分块数在 \(300\) 左右。
然后注意点细节什么的就好了。

Code

Day 3

上午的题目还可以, T1 拓扑排序但是写挂了 T2 数据结构还是挂了 T3 网络流 但是好像还是寄了 T4看都没看

T1

题目描述

对于计数问题和期望问题,你们⼀定都不陌⽣。
给定⼀个 \(n\)个点 \(m\) 条边的有向⽆环图,第 \(i\) 条边有\(p_{i}\) 的概率存在,另外 \(1-p_{i}\) 的概率不存
在,求从 \(1\) ⾛到 \(n\) 的路径条数的期望。

输入格式

第⼀⾏两个正整数 \(n\) 和 \(m\),表示点数和边数。
之后m⾏,每⾏三个数 \(u_{i},v_{i},p_{i}\),表示每条边的起点,终点和出现的概率。

输出格式

⼀个⼩数,表示路径条数的期望,保留2位⼩数。

样例输入

 3 3
 1 2 0.5
 2 3 0.5
 1 3 0.5

样例输出

 0.75

数据范围

\(n,m<=10^{5}\),对所有 \(1<=i<=m\) ,满⾜ \(0<pi<1\) ,\(p_{i}\)⾄多两位⼩数。
保证给定的有向图不存在环,保证答案不超过100(不需要考虑精度问题)

题解

拓扑排序, 直接搞就可以, 转移就是每个点的期望到达值再乘上边的存在值。
最后用加法原理合并。
记得一开始拓扑的时候要把所有入度为零的点加进去。
虽然除了1以外其他点的贡献为零, 但是他们可以帮助别的点减少入度。(我在考试时就在这里寄了。)

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 +100;
double ans[N];
struct T{
	int v;
	double val;
}; 
vector <T> tu[N];
int ru[N];
int n, m;
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++){
		int u, v;
		double val;
		cin >> u >> v >> val;
		tu[u].push_back({v, val});
		ru[v] ++;
	}
	queue <int> q;
	for(int i = 1; i <= n; i ++)
		if(!ru[i]) q.push(i);
	ans[1] = 1;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = 0; i < tu[u].size(); i ++){
			int v = tu[u][i].v;
			double val = tu[u][i].val;
			ans[v] += (ans[u] * val);
			ru[v] --;
			if(!ru[v])
				q.push(v);
		}
	}
	cout << fixed<< setprecision(2) << ans[n];
	return 0;
} 

T2

题目描述

给定⼀个 \(n\) 个点堆(不⼀定是⼆叉堆)的结构,每个点的值构成 \(1 \sim n\) 的排列,即每个点的
值都是 \(1 \sim n\) 之间的整数,且任意不同的两点的值不同。根据堆的定义,每个点的值⼤于它的
所有⼦节点。
现在已知其中 \(k\) 个点的值,你需要回答是否存在这样的堆,即是否可能填上剩下 \(n-k\) 个点
的值,使得每个点的值是 \(1 \sim n\)的排列,并且满⾜每个点的值⼤于⼦节点。
你需要分别判定 \(T\) 棵堆。

输入格式

第⼀⾏⼀个正整数 \(T\) 。接下来有 \(T\) 组数据。
每组数据第⼀⾏两个正整数 \(n\)
第⼆⾏ \(n\) 个整数,表示这个堆上每个节点的⽗亲 \(f\),如果 \(f_{i}=0\) 表示根是 \(i\)
第三⾏ \(n\) 个整数,表示每个节点的值 \(v_{i}\),如果 \(v_{i}=0\) 表示该节点的值未知

输出格式

\(T\) ⾏,第 \(i\) ⾏表示第 \(i\) 组数据是否存在这样的堆,如果存在,输出 \(1\) ,如果不存在,输出0。

数据范围

\(T<=100,n<=10^4\)

样例输入


 2
 5
 0 1 2 3 4
 5 4 3 1 2
 13
 0 1 1 1 2 2 2 3 3 4 4 8 8
 13 7 9 0 0 0 0 3 0 0 0 0 0

样例输出

 0
 1

题解

Code

T3

题意描述

⼤学⾥总共有 \(c\) ⻔课,\(t\) 个时间段。每⻔课会在很多时间段开课,且不同时间段开的同⼀
⻔课可能容纳的⼈数不同,具体地,第 \(j\) 个时间段的第 \(i\) ⻔课的⼈数上限是 \(a[i,j]\),如果\(a[i,j]=0\) 则表示该时间段不开放该课程。教室可以容纳的的⼈数最⼤值是 \(N\) ,保证所有的 $ a[i,j]<=N$ 。
每个学⽣每⻔课可以选择在任何⼀个时间段上,但不能在同⼀个时间段上超过⼀⻔课。求⼤
学⾥学⽣⼈数的上限,使得存在⼀种选课的⽅式,每位学⽣的每⻔课都能选上。

输入格式

第⼀⾏三个正整数 \(N\),\(c\) 和 \(t\),分别表示教室⼤⼩,课程数量和时间段数量。
之后 \(c\) ⾏,每⾏ \(t\) 个⾮负整数,第 \(i\) ⾏第 \(j\)个整数 \(a[i,j]\) 表示第 \(i\) ⻔课在第 \(j\) 个时间段的⼈数上限。

输出格式

⼀个⾮负整数,表示⼤学⾥学⽣⼈数的上限。

数据范围

$ N,c,t<=50 $

样例输入

 3 2 3
 3 1 0
 3 1 0

样例输出

 2

题解

Code

T4

题意描述

给定⼀张 \(n\) 个点 \(m\) 条边的⽆向图,求出所有⽣成树中,以 \(1\) 为根的情况下所有节点的深
度之和的最⼤值,其中树上节点的深度表示该节点到根的路径上的节点个数,包括该节点本身和根节点。

输入格式

第⼀⾏两个正整数 \(n\) 和 \(m\) ,表示点数和边数。
之后 \(m\) ⾏,每⾏两个整数 \(u\) 和 \(v\) ,表示每条边的端点。

输出格式

⼀个整数,表示所有节点深度之和的最⼤值。

数据范围

$ n \le 20, m \le n * (n - 1) / 2$

样例输入

 3 3
 1 2
 1 3
 2 3

样例输出f

 6

题解

Code

下午

下午讲图论

T1 ABC262E

T2 CSP-S2021交通规划

T3 Noi2022 挑战 NPCll (【模板】树同([BJOI2015]
树的同构))

T4 CCO2022 P5 Phone Plans

T5 ABC261Ex

T6 AGC056C

T7 CF1519F

T8 CF1525F

T9 CF1508C

T10 CF1712F

Day 3

上午
只会T1, 其他的全不会

T1 Doctor

题目描述

给定一棵 \(n\) 个点的树和参数 \(k\),你需要找到一条起点为 \(1\) 的路径,满足路径上恰好有 \(k\) 个不同的顶点,且路径的长度最短。一条路径的长度定义为路径经过的点数。

注意,你不需要保证路径是一条简单路径,即路径可以经过重复点和重复边。

输入格式

本题有多组数据。
输入的第一行包含一个正整数 \(T\),分别表示测试数据组数。

对于每一组测试数据:
输入的第一行包含两个正整数 \(n , k\),分别表示树的顶点数和要求经过的不同的顶点数。

接下来 \(n - 1\) 行,每行两个整数 \(u, v\),表示树上存在一条连接顶点 \(u\) 和顶点 \(v\) 的边。

输出格式

对于每一组测试数据:
第一行包含一个正整数 \(m\),表示路径的长度。

第二行包含 \(m\) 个正整数,描述树上的一条路径,其中第 \(i\) 个正整数表示路径上第 \(i\) 个结点的编号。

数据范围

$ 1 \le n, m \le 10^{5} $

样例输入

 2
 6 4
 1 4
 2 5
 1 6
 1 3
 1 2
 6 4
 1 2
 5 6
 1 4
 2 5
 1 3

样例输出

 5
 1 4 1 2 5 
 4
 1 2 5 6 

题解

Code

T2 Patriot

题目描述

给定 \(m\) 个集合 $S_1 \sim S_m $,计数长度为 \(n\) 的整数序列 \(a\)的个数,使得对于任意 \(i\),$ 0 \le a_i \le r $ 且由 \(a\) 导出的长度为 \(m\) 的序列 $ b_i = \bigoplus\limits_{j \in S_i}a_j$ 是一个不降序列(定义空集的 \(b_i\) 为 $ 0 $),即对于 $ 1 \le i < m,b_i \le b_{i + 1} $。其中 $ \oplus$ 表示异或运算。

由于答案可能很大,请输出答案 \(mod\) $998244353 $ 的值。

输入格式

第一行包含两个整数 \(n,m\)表示序列长度和集合的个数。
接下来 \(n\) 行,每行包含一个用二进制形式表示的正整数,其中第 \(i\) 行的正整数表示 \(r_i\) ,含义见题目描述。

接下来 \(m\) 行,每行包含长度为 \(n\) 的 01 串,第 \(i\) 行描述集合 \(S_i\) ,其中第 \(i\) 个序列的第 \(j\) 个字符为 \(1\) 表示 $ j \in S_i$,为 \(0\) 表示 \(j \not\in S_i\)。

输出格式

一行一个整数,表示答案 \(mod\) \(998244353\) 的值。

数据范围

$ 1 \le n, m \le 7, 1 \le r_i \le 2^{500} - 1$

样例输入

 3 4
 110
 101
 100
 111
 101
 011
 010

样例输入

 10

题解

Code

T3 Talulah

题目描述

给定一个长度为 \(n\) 的排列 \(p\) ,定义集合 \(S_i = \{ x | x \ge i \enspace \max\limits_{i \le k < x} p_k < p_x \}\) 。你需要回答一共 \(q\) 组询问,对于第 \(i\) 组询问,给定区间 $ [l_i, r_i] $,你需要求出 $ \sum\limits_{l \le x, y \le r} |S_x \cup S_y|$的值。

输入格式

第一行包含三个正整数 \(n, 1, type\) ,表示排列的长度,询问次数以及 \(p\) 是否随机生成( \(type = 1\)表示 \(p\) 随机生成)。

第二行包含 \(n\) 个正整数,描述排列 \(p\) ,其中第 \(i\) 个正整数表示 \(p_i\) 的值。

接下来 \(q\) 行,每行包含两个正整数 \(l_i,r_i\) 描述一组询问。

输出格式

共 \(q\) 行,其中第 \(i\) 行包含一个正整数,表示第 \(i\) 组询问的答案。

数据范围

$ 1 \le n, q \le 2,5 * 10^{5} $

样例输入

 5 5 0
 3 1 4 5 2
 1 2
 3 5
 2 5
 1 3
 1 5

样例输出

 14
 18
 41
 28
 72

题解

Code

T4 Rosmontis

题目描述

求有序正整数序列对 \((A,B)\) 的数量,满足 \(A_i,B_i \in [1,k]\) ,$ |A| = |B| = n $且存在方案使得从 \(A\) 中删去至多两个元素, \(B\) 中删去至多两个元素后,满足 \(A=B\)。

由于答案可能很大,请输出答案 \(mod \enspace 10^{9} + 9\)的值。

输入格式

第一行包含两个正整数 \(n, k\),分别表示序列的长度和序列的值域。

输出格式

一行一个整数,表示答案模 $ 10^9 + 9$ 的值。

数据范围

$ 1 \le n, k \le 10^9 $

样例输入1

 3 3

样例输出1

 687

样例输入2

 4 7

样例输出2

 2165779

题解

Code

Day 4

T1 equal

上午一道题目都不会, 题目又没有好好讲的, 感觉最近有点寄。

题目描述

有一个长度为 \(n\) 的序列,你要切三刀,把这个序列分成连续的 \(4\) 段,每段的权值
为这段所有数之和, 你要让这四个权值的极差最小。

输入格式

第一行一个整数 \(n\) 。
第二行 \(n\) 个整数,第 \(i\) 个数为 \(a_i\)。

输出格式

一个整数表示最小的四段的极差。

数据范围

$ 4 \le n \le 200000, \enspace 1 \le a_i \le 10^9 $

样例输入

 5
 3 2 4 1 2

样例输出

 2

题解

其实本题很简单(但是在考试的时候没有想到)。
先枚举中间点, 然后把东西分成两部分, 然后再对两部分进行操作。
显然那两部分的极差最小时整体的极差最小, 可以用二分来做。
然后可以发现, 当中间点向左移动一格时, 左右两边的断电也至多会向右移动一格, 所以可以在线性时间内通过此题。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 100;
int n;
long long a[N]; 
long long asum[N];
long long get(int l, int r){
	long long ll = l, rr = r;
	while ( ll < rr){
		int mid = (ll + rr) >> 1;
		if(asum[mid] - asum[l - 1] < asum[r] - asum[mid])
			ll = mid + 1;
		else 
			rr = mid;
	}
	return ll;
}

long long check(int l, int mid, int r){
	long long len[5];
	len[1] = asum[l], len[2] = asum[mid] - asum[l], len[3]= asum[r] - asum[mid], len[4]= asum[n] - asum[r];
	sort(len + 1,len + 1 + 4);
	return len[4] - len[1];
}
int main(){
	cin >> n;
	asum[0] = 0;
	for(int i = 1; i <= n; i ++)
		cin >> a[i], asum[i] = asum[i - 1] + a[i];
	int mid = 2;
	int l, r; // 规定第一段的值为 asum[l] 第二段为 asum[mid] - asum[l] 第三段为 asum[r] - asum[mid]  第四段为 asum[n] - asum[r] 
	long long ans = 0x3f3f3f3f3f3f3f3f; 
	for(mid = 2; mid <= n - 1; mid ++){
		int ll= get(1, mid), rr = get(mid + 1, n);
		for(int i = -1; i <= 1; i ++)
			for(int j = -1; j <= 1; j ++){
				int cl = ll + i, cr = rr + j;
				ans = min(check(cl, mid, cr), ans); 
			} 
	}
	cout << ans;
	return 0;
} 

T2 dance

题目描述

有一个长度为 \(n\) 的序列,对于序列中的每一个数你都需要求出,所有包含这个数
且长度在 \(l\) 到 \(r\) 范围内的连续子序列中,最大的连续子序列的权值和。

输入格式

第一行三个整数 \(n\), \(l\), \(r\)。
第二行 \(n\) 个整数,第 \(i\) 个数为 \(a_i\)。

输出格式

一行 \(n\) 个整数,第 \(n\) 个整数表示 \(f_i\)。

数据范围

$ 1 \le l \le r \le n \le 10^5, \enspace 0 \le |a_i| \le 10^5$

样例输入

 5 1 3
 -1 -6 7 7 -4

样例输出

 0 8 14 14 10

题解

Code

T3 practice

题目描述

你有一个数 \(a\),你想要把它变成 \(b\) ,每次你可以选择一个 \([1, k]\) 范围内的整数 \(x\),假
设当前的数为 \(p\),你可以把 \(p\) 变成 \(p - (p \enspace mod \enspace x)\),特别的,当你选择 \(x = 1\) 时,\(p\) 会变成 \(p - 1\) ,问你至少使用多少次操作才能把 \(a\) 变成 \(b\)。

输入格式

一行一个整数 \(T\),表示有 \(T\) 组数据。
接下来 \(T\) 行每行 \(3\) 个数 \(a\), \(b\), \(k\)。

输出格式

输出 \(T\) 行每行一个整数表示答案。

数据范围

\(1 ≤ T ≤ 10,\enspace b ≤ a ≤ 10^{18},\enspace 1 ≤ k ≤ 15\)。

样例输入

 3
 10 1 4
 6 3 10
 1000000000000000000 1 3

样例输出

 6
 2
 666666666666666667

题解

Code

T4 subsets

题目描述

给定一个由整数组成的集合,问有多少个非空子集,子集中的数能划分成和相等的
两份。集合中的数是可以重复的。

输入格式

一行一个整数 \(n\),集合的大小。
接下来 \(n\) 行,第 \(i + 1\) 行的数 \(a_i\) 表示集合里第 \(i\) 个数。

输出格式

行一个数,表示方案数。

数据范围

$ n \le 20, \enspace |a_i| \le 10^8 $

样例输入

 4
 1
 2
 3
 4

样例输出

 3

题解

考试的时候总觉得像背包, 因为看错题目了。
其实只要输出可行的子集, 而我看成了具体的方案数, 导致写了一个很烦的背包然后成功保灵。
其实就是简单的状压加折半搜索。
可以考虑我们要把一个子集分成两个集合 \(A\) 和 \(B\), 然后记 \(A\) 中元素总和 减去 \(B\) 中元素总和为 \(s\)。
然后考虑一个元素 \(a_i\) , 以及当前状态 \(sta\) ,有三种情况:

  1. 不选, 对 \(s\) 和 \(sta\) 都没有影响
  2. 选, 放进 \(A\) , \(s + a_i , sta \enspace | \enspace (1 << (i - 1))\)
  3. 选, 放进 \(B\) , \(s - a_i , sta \enspace | \enspace (1 << (i - 1))\)

然后就处理出了半部分所有差值为 \(s\) 的状态 然后Hash一下, 后面要用。
思考, 前半部分差值为 \(s\) 后半部分差值为 \(-s\) 的两种分法合并在一起是不是就可以了。
所以在后半段结束时调用出之前Hash进的相应状态, 再取或运算, 这就是合法的状态。
因为每种子集只算一次, 考虑把合法的状态存进一个 \(bool\) 数组。
最后的答案就是把 \(bool\) 数组里的 \(1\) 全部加起来。
记住, 不能有空集。

Code

#include <bits/stdc++.h>
using namespace std;
int n;
const int N = (1 << 20) + 114514;
map <int, int> id;
int cnt = 0;
vector <int> Hash[N];
#define ll long long
ll a[23];
bool an[N];
int mid;
void dfsl(int dep, int s, int state){
	if(dep == mid + 1){
		if(!id[s]) id[s] = ++ cnt;
		Hash[id[s]].push_back(state);
		return;		
	}
	dfsl(dep + 1, s, state); //不选
	dfsl(dep + 1, s + a[dep], state | (1 << (dep - 1)));
	dfsl(dep + 1, s - a[dep], state | (1 << (dep - 1)));
}
void dfsr(int dep, int s, int state){
	if(dep == n + 1){
		if(!id[s]) return ;
		int k = id[s];
		for(int i = 0; i < Hash[k].size(); i ++)
			an[state | Hash[k][i]] = 1;
		return;
	}
	dfsr(dep + 1, s, state); //不选
	dfsr(dep + 1, s + a[dep], state | (1 << (dep - 1)));
	dfsr(dep + 1, s - a[dep], state | (1 << (dep - 1)));
}
int ans = 0;
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
		scanf("%lld", &a[i]);
	mid = n / 2;
	dfsl (1, 0, 0); 
	dfsr (mid + 1, 0, 0);
	for(int i = 1; i <= (1 << n); i ++)
		ans += an[i];
	cout << ans;
	return 0;
}

Day 5

T1

题目描述

小Q和小王在博弈。
对于所有 $ 1 \le i \le n$,桌子上有 \(a_i\) 个数字 \(i\)。 小Q和小王轮流操作,小Q先手。每次操作可以选任意两个相等的数 \(x\),从桌子上拿走这两个数,并再放入一个 $ x + 1 $。
无法操作的人就输了。如果两人都采取最优策略,问谁会赢。
一个测试点含有多组数据。

输入格式

第一行一个整数 \(T\),表示测试组数。
接下来 \(T\) 组每组第一行一个整数 \(n\),第二行 \(n\) 个整数表示 \(a_1, a_2 , ...a_n\)

输出格式

\(T\) 行,每行一个大写字母表示该组测试的答案。若小Q会赢输出 \(Q\) ,否则输出 \(W\) 。

数据范围

$ T \le 10, /ensapce n \le 10^5, \enspace 0 \le a_i \le 10^9$

输入样例

 2
 1
 2
 2
 2 1

输出样例

 Q
 W

题解

这道是个诈骗题, 看上去是博弈论其实不是。
可以发现,这个游戏跟决策没有关系, 因为只要拿两个就可以。只要考虑总的操作次数就可以。
每一次操作会对后面一堆有影响, 所以从前往后做。
再注意 \(n\) 后面的数可能对答案也有贡献, 加上去就可以。
每一次做要将数组清零。

Code

 #include <bits/stdc++.h>
using namespace std;
int T;
#define ll long long
const int N = 2e5 + 100000;
ll a[N];
void solve(){
	int n;
	memset(a, 0, sizeof(a));
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
		scanf("%lld", &a[i]);
	ll res = 0;
	for(int i = 1; i <= n; i ++){
		res += a[i] / 2;
		a[i + 1] += a[i] / 2;
		res %= 2;
	}
	int k = n + 1;
	while(a[k]){
		res += a[k] / 2;
		a[k + 1] = a[k] / 2;
		k ++;
		res %= 2;
	}
	if(res) printf("Q\n");
	else printf("W\n");
}
int main(){
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);
	scanf("%d", &T);
	while (T --)
		solve();
	return 0;
} 

T2

题目描述

你有一个长度为 \(n\) 的序列 \(a_1, a_2...a_n\) 。
你需要进行 \(m\) 次操作。

  1. 给定 \(p\),\(x\) 将 \(a_p\) 赋值为 \(x\)。
  2. 给定 \(l, r, k\) 将所有 \(l \le i \le r\) 的 \(a_i\) 赋值为 \(a_i \enspace mod \enspace k\)。( \(mod\) 为取模运算)
  3. 给定 \(l,r\) 求所有 $l \le i \le r $ 的 \(a_i\) 的最大值。

输入格式

第一行两个整数 \(n, m\)。
第二行 \(n\) 个整数 \(a_1, a_2, ... , a_n\)。
接下来 \(m\) 行每行第一个整数表示操作类型,后面 \(2\) 或 \(3\) 个整数表示这次操作给定的参数。

输出格式

对于所有操作 \(3\),输出一行一个整数表示这次操作的答案。

数据范围

\(n, m \le 10^5, 1 \le a_i, x, k \le 10^9, 1 \le l \le r \le n\)。

输入样例

 3 5
 2 3 3
 3 1 3
 2 2 3 2
 3 1 3
 1 2 5
 3 2 3

输出样例

 3
 2
 5

题解

线段树, 暴力操作。
若子树的最大值小于模数, 就不去修改。

Code

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 1000;
int n, m;
struct Tr{
	ll val;
}tr[N * 8];
ll a[N];
void push_up(int rt){
	tr[rt].val = max(tr[rt << 1].val, tr[rt << 1 | 1].val);
	return;
}
void build(int rt, int l , int r){
	if(l == r){
		tr[rt].val = a[l];
		return;
	}
	int m = (l + r) >> 1;
	build(rt << 1, l, m);
	build(rt << 1 | 1, m + 1, r);
	push_up(rt);
	return ; 
}

bool check(int rt, ll p){
	if(tr[rt].val < p) return false;
	return true;
}
void change(int rt, int l, int r, ll p, ll x){
	if(l == r){tr[rt].val = p; return;}
	int m = (l + r) >> 1;
	if(m >= x) change(rt << 1, l, m, p, x);
	else change(rt << 1 | 1, m + 1, r, p, x);
	push_up(rt);
}

void update(int rt, int l, int r, int L, int R, ll k){
	if(l == r){tr[rt].val %= k; return;}
	int m = (l + r) >> 1;
	if(L <= m && check(rt << 1, k)) update(rt << 1, l, m, L, R, k);
	if(m < R && check(rt << 1 | 1, k)) update(rt << 1 | 1, m + 1, r, L, R, k);
	push_up(rt);
}

ll query(int rt, int l, int r, int L, int R){
	if(L <= l && r <= R) return tr[rt].val;
	int m = (l + r) >> 1;
	ll ans = -19090;
	if(L <= m){
		if(tr[rt << 1].val == 0) ans = max(ans, (ll)0);
		else ans = max(ans, query(rt << 1, l, m, L, R));
	}
	if(m < R){
		if(tr[rt << 1 | 1].val == 0) ans = max(ans, (ll)0);
		else ans = max(ans, query(rt << 1 | 1, m + 1, r, L, R));
	}
	return ans;
}
int main(){
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= n; i ++)
		scanf("%lld", &a[i]);
	build(1, 1, n);
	for(int i = 1; i <= m; i ++){
		int pos;
		scanf("%d", &pos);
		if(pos == 1){
			ll p, x;
			scanf("%lld%lld", &p, &x);
			change(1, 1, n, x, p);
		}
		if(pos == 2){
			int l, r;
			ll k;
			scanf("%d%d%lld", &l, &r, &k);
			update(1, 1, n, l, r, k);
		}
		if(pos == 3){
			int l, r;
			scanf("%d%d", &l, &r); 
			printf("%lld\n", query(1, 1, n, l, r));
		}
	}
	return 0;
}

T3

题目描述

给定 \(n\),求所有长度为 \(n\) 的错排的逆序对数之和。
一个测试点含有多组数据。
答案对 $998244353 $取模。

输入格式

第一行一个整数 \(T\),表示测试组数。
接下来 \(T\) 行每行一个整数 \(n\)。

输出格式

\(T\)行, 每行一个整数表示这组数据的答案。

数据范围

$ T \le 2 * 10^5 \enspace n \le 10^7 $

输入样例

 3
 2
 3
 114514

输出样例

 1
 4
 556483447

题解

Code

T4(TL = 3s)

题目描述

现在是晚上九点,小王准备为大家献歌一首。
小王要唱的歌的歌词可以抽象成一个长度为 \(n\) 的字符串 \(s\),其中每个字符可能是大小写字母,数字,下划线。
(注:大小写相同字母视为不同的字符)
现在,小Q会进行以下 \(m\) 次操作,每次操作给定 \(l, r, t\):

  1. 小Q为了让小王唱的更魔怔,把歌词的第 \(l\) 个字符到第 \(r\)个字符替换为长度为 \(r - l + 1\) 的字符串。
  2. 小Q想检验小王唱的怎么样,让小王从第 \(l\) 个字符唱到第 \(r\) 个字符。他想知道在这个过程他总共会听到多少次 \(t\) 。即 \(t\) 在 \(s[l,r]\) 中共可重叠出现了多少次。
    由于训练小王唱歌不是一件轻松的事,所以小Q请你写一个程序来帮他训练小王并回答每次询问。

输入格式

第一行两个整数 \(n, m\)。
接着一行长度为 \(n\) 的字符串 \(s\)。
下面 \(m\) 行每行开头一个 \(1\) 或 \(2\)表示操作类型,然后是两个正整数 \(l,r\) 和一个字符串 \(t\)。

输出格式

对于每次 \(2\) 操作,输出一行表示答案。

数据范围

\(1 \le n, m \le 10^5, \enspace 1 \le k_1 \le 2 * 10^6, \enspace 1 \le k_2 \le 10^5\)
其中,\(k_1\) 为所有 1 操作中的 \(t\) 长度之和, \(k_2\) 为所有 \(2\) 操作中的 \(t\) 长度之和。

输入样例

 34 10
 JinWan9Dian_WHQChangGe_BuJianBuSan 
 2 1 34 an 
 2 6 33 an 
 1 1 10 aaaaaaaaaa 
 2 2 9 aaa 
 2 1 34 _ 
 1 11 20 abaabaabab 
 2 1 20 ab 
 2 1 20 aab 
 1 1 34 JinWan9Dian_WHQChangGe_BuJianBuSan 
 2 1 34 JinWan9Dian_WHQChangGe_BuJianBuSan

输出样例

5
3
6
2
4
3
1

题解

Code

Day 6

T1 permutation

题目描述

给两个大小为 \(n\) 的排列 \(p,q\)。
你需要给出另一个大小为 \(n\) 的排列 \(h * p * h^{-1} = q\) 满足 ,或判断不存在这样的排列 \(h\) 。
一些定义:

  • \(p\) 是一个大小为 \(n\) 的排列当且仅当 \(p_i \in \{ 1, 2, ..., n \}\),且 \(p_i\) 两两不同。
    对于两个大小为 \(n\) 排列的 \(p,q\) 定义 \(h = p * q\),其中 $\forall i, h_i, q_{p_i} 。(注意,这里的定义可能与你所了解的定义不同)
    对于一个大小为 \(n\) 的排列 ,定义 为 的逆元,其中 满足

学习清单

prufer
树的同

标签:输出,le,10,int,样例,格式,游记,省常中
From: https://www.cnblogs.com/skadi08/p/16755419.html

相关文章

  • FJOI2022 游记
    2022.3.28省选延期,延到了4.162022.4.11省选又延期,延到了5.2FJOI要回来了!!Day-7开始停课了QwQDay-6打摆Day-5打摆不行,我不能如此堕落Day-4打摆Day-3打......
  • ARC148游记
    A-modM题目链接这道题我们可以首先对于所有的数$%2$,可以证明出答案最多不超过$2$,此时我们就可以把问题转化为:是否存在一个数使得序列$a$中所有元素减去这个数之......
  • CSP 2022 游记
    初赛前今年把普及和提高都报上了,虽然说参加普及组对我来说没啥意义了,但免得防止提高初赛没过导致无赛可比。赛前一两周看到的消息,福建的主办单位从福建计算机学会变成了......
  • CSP2022游记
    CSP2022游记第一轮Day-∞几个月前YC学校分流考试刚刚结束,整个假期都沉迷在成功的狂喜之中(感到人生已经达到了巅峰doge)在假期快乐地学习了高中whk后忽然感到“我郝墙”......
  • CSP-S 2022游记
    娱乐选手。Day-∞初赛84,太逊了!!!不过线只有52,过了。这种分数线真的有人过不了初赛吗......
  • 【补档】CSP2020-J 游记
    (洛谷博客版本)突然发现两年前写的游记已经不知在哪个国家了,于是再写一个。本人坐标GD。去打的时候我才刚升五年级,OI才搞不到一年,刚学完裸dfs,所以没抱多大期望。初赛......
  • 【补档】CSP2021-J 游记
    (洛谷博客版本)前传:CSP2020-J游记上一次拿了2=,这次争取冲1=!主要时间花在复赛内容上面了,初赛没怎么搞。初赛看到前15题一阵狂喜:这次稳了。单选好像只错了两三题的......
  • ICPC2022 Online Contest 2 游记
    总结,8个题,前期罚时爆炸,后期坐牢。开局先找到签到题【E】。题意是给定\(a_1\)要求构造数组\(a_i\),满足\(\gcd(a_i,a_{i-1})==1\)且\(a_i>1\)。显然直接贪一波,......
  • 生地会考游记
    byhukk基本信息坐标:湖南长沙考试时间:2022.6.20下午查分时间:2022.7.222:00起DAY-...:模拟考试会考之前,我们每周都考官方出的模拟卷。得分基本稳在\(190\sim......
  • 「游记」CSP 2022
    9.05+模拟赛日常考不过暴力老哥。天天挂分。烦死了。感觉人要没。9.16坑。9.18初赛。没报J组。S组完善程序中“归并第\(k\)小”的程序完全没看懂,于是填了\(5\)......