DOJ-1910题单总结

纯想

CF353B

本题没有任何技术含量,若同一数出现 2 2 2 次及以上将其中 2 2 2 个分别放到不同堆中,其余统一分配。

CF359C

等图片

CF362C

冒泡排序交换次数等价于数组逆序对数量,暴力枚举交换的 2 2 2 个数,通过维护 2 2 2 个数组 O ( 1 ) O(1) O(1) 求出新数组逆序对数量

CF366C

之前博客里写过,自然会做

自己想+题解点播

CF343C

自己的思考

首先看到最短时间,且时间越长肯定越可以实现,所以最短时间方面可以进行二分
对于每个读取口,我想到了它可以一直往右或左、先往左再往右、先往右再往左的运动状态但并没有想到读取口该如何运动?

题解给的启发

首先时间是定的,对于所有读取口尽可能希望其能覆盖尽可能多的信息。
对于边界的读取口,用它读取同向边界的信息一定是很优秀的,所以对于边界的读取口,必须先将边界信息读取,再往回读取尽可能多的信息,不断出现新的边界,最终完成。

等图片

坑点

注意对于每个时间节点下的左边界,必须让其读取到那个时间点下最左边的信息(若它不能读到,其它节点必不能读到)。

反思

对于这道题,应先找到特殊的地方,读取头在边界的最特殊,应从它开始分析,我们的目的是让时间最少,时间最少代表每个读取头利用价值最大,也就代表要物尽其用从特殊考虑。

CF372B

一道典型的纯优化型dp,很有数学含量

O ( n 6 ⋅ q ) O(n^6 \cdot q) O(n6q)(2定+暴力)

对于每个询问,直接枚举每个矩阵(左上,右下),暴力计算矩阵和。

O ( n 4 ⋅ q ) O(n^4 \cdot q) O(n4q) (2定+二维前缀和)

提前用二维前缀和维护矩阵和,对于每个询问,直接枚举每个矩阵(左上,右下),通过二维前缀和调用矩阵和。

O ( n 2 ⋅ q ) O(n^2\cdot q) O(n2q)(1定1动+2*二维前缀和)

定义 g i , j , l , r g_{i,j,l,r} gi,j,l,r 表示以 ( i , j ) (i,j) (i,j) 为左上角,右下角在以 ( i , j ) 和 ( l , r ) (i,j)和(l,r) (i,j)(l,r) 分别为左上角和右下角的矩形内的所有矩阵中矩阵和为 0 0 0 的矩阵数量。
对于每个询问,直接枚举每个矩阵(左上),通过 g [ ] [ ] [ ] [ ] g[][][][] g[][][][] 调用矩阵和为 0 0 0 的矩阵数量。

O ( q ) O(q) O(q)(2动+3*二维前缀和)

先维护 g [ ] [ ] [ ] [ ] g[][][][] g[][][][]
定义 f i , j , l , r f_{i,j,l,r} fi,j,l,r 表示以 ( i , j ) 和 ( l , r ) (i,j)和(l,r) (i,j)(l,r) 分别为左上角和右下角的矩阵的所有子矩阵中矩阵和为 0 0 0 的矩阵数量.
对于每个询问,通过 f [ ] [ ] [ ] [ ] f[][][][] f[][][][] 调用矩阵和为 0 0 0 的矩阵数量。

CF374C

坑点

记录DIMA 数量的 d i s [ ] [ ] dis[][] dis[][] 可以记录按照顺序经过的字母数量,其连续 DIMA 数量为 ⌊ m a x ( d i s [ ] [ ] ) / 4 ⌋ \lfloor max(dis[][])/4 \rfloor max(dis[][])/4

纯题解点播

CF356B

首先我们缩小范围,只需要研究 l c m ( l e n a , l e n b ) lcm(lena,lenb) lcm(lena,lenb) 长度的价值,最后在乘上 l e n a ⋅ n l c m ( l e n a , l e n b ) \frac{lena\cdot n}{lcm(lena,lenb)} lcm(lena,lenb)lenan
若罗列 l c m ( l e n a , l e n b ) lcm(lena,lenb) lcm(lena,lenb) 长度字符串我们会发现 f o r a l l a i forall a_i forallai 都恰好与 b j ( i m o d    gcd ⁡ ( l e n a , l e n b ) = j m o d    gcd ⁡ ( l e n a , l e n b ) ) b_j(i \mod \gcd(lena,lenb)=j \mod \gcd(lena,lenb)) bj(imodgcd(lena,lenb)=jmodgcd(lena,lenb)) 对应一次

CF351B

主要是态度问题,期望的题还是要想15min的。

直观思路

我们将 2 2 2 个人的策略分开讨论:
Jeff: 肯定会减少 1 1 1 个逆序对
Fruik: 50% -> +1 50%->-1 ,综上期望上逆序对数不变
结合 2 2 2 个人分别操作一次,期望减少的逆序对数量为 1 1 1

因此,设原数组逆序对数量为 t o t tot tot
t o t tot tot 为偶数 答案为 2 t o t 2tot 2tot
否则 答案为 2 t o t − 1 2tot-1 2tot1

严谨思路

首先根据期望的线性性和可加性,开始进行dp转移。
定义 f i f_i fi 表示有 i i i 个逆序对所要进行的操作数期望
状态转移方程: f i = 1 2 ( f i − 2 + 2 ) + 1 2 ( f i + 2 ) f_i=\frac{1}{2}(f_{i-2}+2)+\frac{1}{2}(f_i+2) fi=21(fi2+2)+21(fi+2)
变换一下转移方程得到: f i = f i − 2 + 4 f_i=f_{i-2}+4 fi=fi2+4
∵ f 0 = 0 , f 1 = 1 \because f_0=0,f_1=1 f0=0,f1=1
∴ f i = [ i m o d    2 = 1 ] ⋅ ( 2 i − 1 ) + [ i m o d    2 = 0 ] ⋅ 2 i \therefore f_i=[i \mod 2=1]\cdot(2i-1)+[i \mod 2=0] \cdot 2i fi=[imod2=1](2i1)+[imod2=0]2i
完整且严谨

期望可加性证明:
等图片

CF367B

map 可以直接比较是否相等

#include<bits/stdc++.h>
#define int long long 
using namespace std;

const int maxn=2e5+10;
int n,m,p,l,r,num;
int a[maxn],ans[maxn];
map<int,int>b,cnt;
inline void ipt(){
	scanf("%lld%lld%lld",&n,&m,&p);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=m;i++){
		int x;
		scanf("%lld",&x);
		b[x]++;
	}
}
inline void solve(){
	for(int i=1;i<=p;i++){
		cnt.clear();
		l=r=0;
		for(int j=i;j<=n;j+=p){
			++r;
			cnt[a[j]]++;
			if(r-l==m){
				if(b==cnt)ans[++num]=j-(m-1)*p;
				cnt[a[j-(m-1)*p]]--;
				if(cnt[a[j-(m-1)*p]]==0)cnt.erase(a[j-(m-1)*p]);
				++l;
			}
		}
	}
}
inline void opt(){
	sort(ans+1,ans+num+1);
	printf("%lld\n",num);
	for(int i=1;i<=num;i++)printf("%lld ",ans[i]);
	printf("\n");
}
signed main(){
	ipt();
	solve();
	opt();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

materialistOier

我只是一名ssfoier

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值