A.选择
方法一:固定中位数的思想。先对数组从左到右按非递减顺序排序,枚举第个元素作为中位数的情况,那么我们只需要在满足第
个元素是中位数的前提下选择尽可能多的元素。如何保证第
个元素是中位数?令位置
左边的元素选了
个,位置
右边的元素选了
个,只需要满足
或
即可。如何在此条件下选择最多的元素?令位置
左边有
个元素,位置
右边有
个元素,令
,那么取
最优。
方法二:通过证明结论减少方案的选择。先对数组从左到右按非递减顺序排序,如果记,那么只需要考虑中位数对应下标
满足
的情况而不需要考虑
的情况,证明显然:考虑对于所有
的情况,对所选元素下标按照中心位置对称,即对于所选下标
都改成
后一定合法且不劣,因为所选大小不变,而中位数可能不变或增大。因此直接枚举所有下标
作为左端点下标
作为右端点的连续区间更新答案即可。
B.ljl的魔方矩阵
因为中间的数给定了,那么行和其实也给定了,就是中间这个数的三倍。然后每次暴力判断每行、每列、对角线是否只缺一个数,判断六次即可,这样操作后会出现两种情况。
- 此时所有的数已经全部填好了。
- 此时缺少四个角的数,这种情况处理一下即可。
标程给的是更一般的解法,即中间的数不给定也可以处理,先通过线性代数的知识解出三个基础解系,然后用给定的三个数构造出三元一次方程组。解出系数即可。
C.交换
根据本题的数据范围,将使用DP进行解题。
假设次操作要加的数组下标为
。显然,加到总分里的数不可能为
,并且
(后面大的数只会往前移动,不可能把前面大的数移到后面进行处理)。于是问题转化为求
。
定义表示第
次操作,
,且已经进行
次交换最多可以得到的分数。
分以下两种情况进行转移:
:对于这种情况,转移为
。
:首先,
,所以把
的数移到
的位置需要
次移动。所以
。这里可以使用前缀最大值优化,使得计算
只需要
的时间复杂度。
总的时间复杂度为。
D.狭义"LJL"
签到题。 读入整行字符串,对连续的三个字母判断是否是"ljl",如果是则跳过这三个字母,输出"ncljr",否则输出当前字母。 使用python可3行秒杀。
E.上升还是下降
题目大意:
给定一个长度为的排列,每人轮流操作,最后序列变成升序则ljl获胜,变成降序则ljr获胜,如果分不出胜负则平局。
题解
统计三个值,只有ljl需要操作的数的数量,只有ljr需要操作的数的数量
,ljl和ljr
都需要操作的数的数量
。
如果,此时ljl和ljr的策略都是独立的,由于ljl先手,所以
时ljl获
胜,不然ljr获胜,不会出现平局情况。
时,来看
和
的关系。如果
,此时ljl没有获胜的可能,所以此时只会出现卢减亮获胜或者平局的情况。如果
,ljr获胜,不然平局。同样的,如果
,此时只会出现ljl获胜或者平局的情况,如果
,ljl获胜,不然平局。
F.感谢庆典的MEX
题意:已知长度为 的序列
,定义一次操作的过程为:选择任意一个元素,随后将
从原序列中删除,并将
(向下取整)添加回原来的位置。你可以进行任意多次操作(也可以一次操作都不做),要求使得序列的
最大,求这个最大的
值。
首先我们发现题目给的数值特别大,而这题实际上最大的也不会超过
,因为
为没有出现在数组中的最小非负整数。那么由于只有
个数字,所以最坏情况是所有数字从
出现一次,那么答案就会是
,否则由于有一些数字大了导致
中有空值了,就会取到那个值而不会更大,所以答案一定
。
知道这个性质有什么好处呢?这为之后的二分和特判埋下了伏笔。
这里先看,如果我们求出了答案为
,那么是不是相当于
的数都出现过了,而
没有出现过,所以假设我们求出了一个值
在
,那么
一定满足是
的,因为我们可以一直除以
达到让答案变成
,如果
大于等于
,那么由于
不可能在数组那个数组中出现,一定不能作为答案,所以我们会发现答案具有二段性,小于
的都可以变大,大于
的都必须变小,那么我们就确定了上下界为
(为什么不为
,因为
一定可以将一个数一直除到
,那么最小答案一定为
)。那么我们就可以二分枚举答案,再判断一下
是不是都能被构造出来。那么问题就变成了我们要将数组除以
使得所有
的数值都要出现。
判断的时候就可以贪心去想了,记二分中点为,首先所有小于
的值
我们都可以先在数值为
位置填上,如果重复了就直接除以
,直到到达一个没有填过的位置,如果变成
了还没有位置就停止,所有大于等于
的数值都可以直接除以
变小,直到到达
以内第一个没有填过数值的位置,然后填上,如果变成
了还没有位置就停止。然后检查下
的每个位置上是否有数,如果都有就让二分的左端点变成
,否则就让右端点变成
。
证明贪心正确:
首先是如果有一个位置只有一个数能到达,那么它一定要在那个位置上,如果前面还有它能到达的,但是没有数字填上去,那么它如果到前面的位置了一定会空出当前位置导致有一个值没出现,一定会让mid变小,所以这样到达以内的第一个位置一定更优。
而如果有一个位置有两个及以上的数字能够到达,那么我们让后面到达的数向前走,两个是等价的,所以一定可以得到更优解。(这里可以用跟最优解比较法进行比较以得出这种贪心一定更优)。
所以证明贪心正确。
由于二分有个,而如果将
对
整除最多进行
次左右,枚举位置为
。所以最坏时间复杂度为
,大约为
左右,可以通过本题,但是建议先将所有
先除到
以内,因为
以为都为无解(上证明过),这样可以快大约
倍左右。
你们以为结束了吗?还没有,这里有一个坑人的点,就是任何数除以都为本身,所以当
时要特判,这就是简单的求一个数组的
的问题,这个可以先对数组离散化,然后找出从
第一个没有出现的数输出。也可以先把所有数插入
中,然后找出从
第一个没有出现在
中的数输出。时间复杂度为
。
所以总的时间复杂度为。
G.约数
问题为求,可以转化为求
。
对于,如果挨个求
,那么时间复杂度为
,会超时。转化一下思路,对于一个正整数
,它在
中出现了多少次?由于
中
的倍数有
个,所以
的约数和为
。
所以,。显然,现在可以采用整除分块去计算。对于一段区间
来说,其
值是相同的,但是
的值不同,需要利用等差数列公式计算出这一段区间的
之和,然后与
相乘便是这段区间
的贡献。注意整个计算过程要取模。
时间复杂度为。
H.ljl要不对称的美
题目类型:字符串
这道题目数据规模较大,进行暴力肯定会超时。所以面对每次查询,我们必须要用 的时间复杂度去处理。
注意到:
-
当真子串长度
时,该子串被认为是对称子串 ,所以一律不考虑。
-
当区间串中的所有字符都相等时,所有偶数的长度 (
)都不可计入答案,否则都可计入。
如 "aaaaaaa" 查询 "1 7",可以发现找不出长度为 2 、 4 和 6 的非对称字符串;
而 "aaaaaab" 查询 "1 7",即可找到非对称字符串"ab"、"aaab"、"aaaaab",从而 答案+=3。
-
当区间串中所有偶数位的字符相等,所有奇数位的字符相等,则所有奇数的长度 (
)都不可计入答案,否则除
外都可计入。
如"abababa" 查询 ”1 7“,可以发现找不出长度为 3 和 5 的非对称字符串;
而"abababc" 查询 "1 7",即可找到非对称字符串 "abc"、"ababc" ,从而 答案+=2。
代码思路:
从左往右存与当前位字符相等的、最近的字符的距离。如"abca",第一个a的相等的最近距离为3。
在查询时只用查找区间中第一位或第二位的最近相等位置,然后按上面这个规律去判断:如果第一位的最近相等的字符没超过区间,则所有偶数的长度计入答案;如果第一位或第二位的步长为2的相等的字符没超过区间,则所有奇数的长度计入答案。(注意!所有查询都是真子串,所以区间长度不计入答案。)
I.数字重组
不妨把这个数字看成一个大小最大为9的数组,
那么重组这个数字的所有可能即为该数组的全排列,时间复杂度为,
。
我们只要暴力枚举所有的情况然后用的时间维护这一排列情况的大小即可。
总时间复杂度为。
如何暴力枚举
1.DFS
ll ans = 0;
bool vis[15];
void dfs(int x) {
if (x == N) {
string t;
for (int i = 0; i < N; i++) {
t += s[p[i]];
}
ans = max(ans, cal(t));
return;
}
for (int i = 0; i < N; i++) {
if (vis[i]) continue;
vis[i] = 1;
p[x] = i;
dfs(x + 1);
vis[i] = 0;
}
}
dfs(0);
2.next_permutation()
for (int i = 0; i < N; i++) p[i] = i;
do {
string t;
for (int i = 0; i < N; i++) {
t += s[p[i]];
}
ans = max(ans, cal(t));
} while (next_permutation(p, p + N));
计算权值
ll cal(string &t) {
reverse(t.begin(), t.end());
ll res = 1;
for (int l = 0; l < t.size(); l += 3) {
int r = min((int)t.size() - 1, l + 2);
int v = 0;
for (int i = l; i <= r; i++) {
v = v * 10 + t[i] - '0';
}
res *= v;
}
return res;
}
J.优雅的字符串
如果中还有两个相同的字符,则输出
。
否则,总是可以通过替换来使得
变成优雅的字符串。做法如下:
顺序扫描
,如果碰到
,需结合前一个字符
和后一个字符
进行判断填写。如果
为
,则只需要填写与
不同的字符即可。如果
不为
,则需要填写与
和
都不相同的字符。为了处理方便,需在
的头尾各加一个
进行扫描。
时间复杂度为。
K.ljl想找到最佳数
签到题。根据题意模拟即可。