20241222 总结

20241222 总结

A - CodeForces - 1350B

简化题意:给定一个长度为 \(n\) 的序列 \(A\),求一个 \(A\) 的长度为 \(m\) 的严格上升子序列 \(B\),设其在 \(A\) 中对应位置为 \(p\) 序列,使得对于任意 \(1\le i < m\) 均有 \(p_i | p_{i+1}\),求满足条件的最大的 \(m\)

思路:首先定义状态 \(f_i\) 表示以 \(i\) 结尾的符合条件的子序列长度,则朴素的转移是枚举两个位置 \(1\le j < i\le n\),每次判断 \(j | i\) 是否成立,成立则 \(f_i\gets\max (f_i,f_j+1)\),这种算法时间复杂度为 \(\Omicron (n^2)\),在 \(1\le n\le 10^5\) 范围内无法通过。考虑优化,我们可以直接枚举 \(i\) 的倍数进行转移,利用数学知识可知,该算法复杂度降为 \(\Omicron (n\ln n)\),可以通过。

细节与难点:此题难点在于正确分析算法时间复杂度,实现未遇到困难。

B - AtCoder - abc275_f

简化题意:给定一个长度为 \(n\) 的序列 \(A\),每次操作可以从其中标记一个连续子段,求使得未标记部分之和为 \(1\le x\le m\) 的最小操作次数。

思路:首先观察到 \(1\le n\le 3\times 10^3\),适合 \(\Omicron (n^2\log n)\) 复杂度以下算法。我们可以定义状态 \(f_{i,j,0/1}\) 表示当前到第 \(i\) 位,前 \(i\) 项中未被标记的数之和为 \(j\),当前位标记(0)/不标记(1)的最少操作次数。则我们定义转移方程:

\[f_{i,j,0}\gets\min\{f_{i,j,0},f_{i-1,j,0},f_{i-1,j,1}+1\} \]

表示第 \(i\) 位标记时,由上一位标记这一位标记、上一位不标记这一位标记转移而来;

\[f_{i,j,1}\gets\min\{f_{i,j,1},f_{i-1,j-a_i,0},f_{i-1,j-a_i,1}\} \]

表示第 \(i\) 位不标记时,由上一位不标记这一位不标记、上一位标记这一位不标记转移而来。这种转移方程使算法时间复杂度为 \(\Omicron (n^2)\),可以通过。边界条件为 \(f_{1,a_1,1}=0,f_{1,0,0}=1\)

细节与难点:此题难点在于转移时的细节,我在这方面出现的问题是 \(f_{i,j,0}\) 转移时因为 \(j\) 没有变化,可以枚举 \(0\sim m\) 中的所有情况,而我只枚举了 \(a_i\sim m\) 中的情况,且初步修改时以为是循环顺序不正确,经老师点拨改正。

C - AtCoder - abc265_e

简化题意:从原点出发,每次可以从 \((x,y)\) 移动至 \((x+a,y+b)\)\((x+c,y+d)\)\((x+e,y+f)\),且不可到达 \((p_1,q_1)\)\((p_2,q_2)\)\(\cdots\)\((p_m,q_m)\)。求移动 \(n\) 次后有多少种不同移动路径。

思路:注意到 \(1\le n\le 3\times 10^2\),且只有三种移动方式,定义状态 \(f_{i,r_1,r_2,r_3}\) 表示共移动 \(i\) 次,其中三种移动方式分别的次数分别为 \(r_1,r_2,r_3\)。枚举上述四变量,则当前点坐标 \((x,y)=(r_1*a+r_2*c+r_3*e,r_1*b+r_2*d+r_3*f)\) ,三个移动后的点如题意,则用 map 判断新点是否可以到达,并扩散转移:

\[f_{i+1,r_1+1,r_2,r_3}\gets f_{i+1,r_1+1,r_2,r_3}+f_{i,r_1,r_2,r_3} \]

\[f_{i+1,r_1,r_2+1,r_3}\gets f_{i+1,r_1,r_2+1,r_3}+f_{i,r_1,r_2,r_3} \]

\[f_{i+1,r_1,r_2,r_3+1}\gets f_{i+1,r_1,r_2,r_3+1}+f_{i,r_1,r_2,r_3} \]

统计答案即为 \(i=n\)\(f_{i,r_1,r_2,r_3}\) 之和。

注意到上述转移复杂度为 \(\Omicron (n^4)\),仍无法通过,注意到 \(r_3=i-r_1-r_2\),可省去一维复杂度,降为 \(\Omicron (n^3)\)

细节与难点:转移基本无难度,但是注意细节:map 判断点是否能到达时不可用中括号访问,这样相当于在 map 中新添加了一对映射,复杂度变劣,应使用 count 或 find 函数,多重循环循环变量需辨认清楚

D - AtCoder - abc244_e

简化题意:给定一个 \(n\) 个点 \(m\) 条边的无向图 \(G\),求其中有多少条首尾分别为 \(S\)\(T\) 的长度为 \(k\) 的路径(不一定为简单路径),满足 \(X\) 点被经过偶数次。

思路:定义状态 \(f_{i,j,0/1}\) 表示经过 \(i\) 条边后到达 \(j\) 点,总共经过偶数(0)/奇数(1)次 \(X\) 点。则我们枚举 \(i\) 、边的起点 \(u\)、边的终点 \(v\),则转移为:

\(v\ne x\) 则:

\[f_{i,v,0}\gets f_{i,v,0}+f_{i-1,u,0} \]

\[f_{i,v,1}\gets f_{i,v,1}+f_{i-1,u,1} \]

表示经过 \(X\) 的次数不变,奇偶性不变;

\(v=x\) 则:

\[f_{i,v,0}\gets f_{i,v,0}+f_{i-1,u,1} \]

\[f_{i,v,1}\gets f_{i,v,1}+f_{i-1,u,0} \]

表示经过 \(X\) 的次数加一,奇偶性变化。

答案即为 \(f_{k,T,0}\)。上述看似枚举了三个变量,实则枚举 \(u,v\) 只有 \(\Omicron (m)\),时间复杂度为 \(\Omicron (km)\)

细节与难点:我使用了一个辅助数组 \(g\) 用来滚掉 \(f\) 数组中 \(i\) 的一维,但是每次没有清空原数组 \(f\) 以达到滚动数组的效果,这样做时需要注意,或者在如本题一样没有卡死空间的题目不滚动,开满维度。

F - CodeForces - 1077F1

简化题意:给定一个长度为 \(n\) 的序列 \(A\),要求从中选出恰好 \(x\) 项,使得 \(A\) 的每个长为 \(k\) 的连续子段都有一项被选中,求选中的项之和的最大值或报告无解。

思路:注意到本题 \(1\le k,x\le n\le 2\times 10^2\) 的较小数据范围,考虑 \(\Omicron (n^3)\) 朴素 DP。我们可以设计状态 \(f_{l,i}\) 表示 \(A_1\sim A_i\) 中选的第 \(l\) 个为 \(A_i\) 的最大和。则我们枚举 \(l,i\)\(1\le l\le x,i\le n\)),再枚举选中的第 \(l-1\) 个数的位置 \(j\)\(\max (0,i-k)\le j < i\)),则有转移方程 \(f_{l,i}\gets\max (f_{l,i},f_{l-1,j}+A_i)\)。则答案即为 \(\max\limits_{i=n-k+1}^{n} f_{x,i}\)

细节与难点:我在初始化出了问题,一开始我没有给 DP 数组 \(f\) 赋初值 \(-\inf\),导致在不满足题意要求的情况下也进行了转移与答案统计。

G - CodeForces - 1077F2

简化题意:同上。

思路:本题数据范围扩大至 \(5\times 10^3\) 级别,注意到上述转移中有 \(f_{l,i}\gets\max (f_{l,i},f_{l-1,j}+A_i)\) 一式,发现其中 \(f_{l-1,j}\) 可以用单调队列动态维护最大值,沿用原式转移即可,时间复杂度 \(\Omicron (n^2)\)

细节与难点:无。注意单调队列模板中的 front 和 back 不要写反。


My Code

A

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

namespace rab {
	int t=-1,n,a[100010],f[100010];

	int main () {
		if (!~t) cin>> t;
		if (!t--) return 0;
		cin>> n;f[0]=0;
		fill (f+1,f+n+1,1);
		for (int i=1;i<=n;i++) cin>> a[i];
		for (int i=1;i<=n;i++)
			for (int j=2;i*j<=n;j++)
				if (a[i]<a[i*j]) f[i*j]=max (f[i*j],f[i]+1);
		for (int i=1;i<=n;i++) f[0]=max (f[0],f[i]);
		cout<< f[0]<< "\n";
		return main ();
	}
}

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}

B

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

namespace rab {
	const int inf=3000;
	int n,m,a[3010],f[3010][3010][2];

	int main () {
		cin>> n>> m;
		for (int i=1;i<=n;i++) {
			cin>> a[i];
			for (int j=0;j<=m;j++)
				f[i][j][0]=f[i][j][1]=inf;
		}
		f[1][a[1]][1]=0;
		f[1][0][0]=1;
		for (int i=2;i<=n;i++) {
			for (int j=m;~j;j--) {
				f[i][j][0]=min ({f[i][j][0],f[i-1][j][0],f[i-1][j][1]+1});
				if (j>=a[i]) f[i][j][1]=min ({f[i][j][1],f[i-1][j-a[i]][0],f[i-1][j-a[i]][1]});
			}
		}
		for (int i=1;i<=m;i++) {
			int ans=min (f[n][i][0],f[n][i][1]);
			if (ans^inf) cout<< ans<< "\n";
			else cout<< "-1\n";
		}
		return 0;
	}
}

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}

C

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

#define i64 long long
#define pii pair<i64,i64>
namespace rab {
	const int mod=998244353;
	int n,m;
	i64 a,b,c,d,e,f,ans,dp[310][310][310];
	map<pii,bool> mp;

	int main () {
		cin>> n>> m>> a>> b>> c>> d>> e>> f;
		for (int i=1,x,y;i<=m;i++) {
			cin>> x>> y;
			mp[{x,y}]=1;
		}
		dp[0][0][0]=1;
		for (int i=0;i<n;i++) {
			for (int r1=0;r1<=i;r1++) {
				for (int r2=0;r1+r2<=i;r2++) {
					int r3=i-r1-r2;
					i64 x=r1*a+r2*c+r3*e;
					i64 y=r1*b+r2*d+r3*f;
					if (!mp.count ({x+a,y+b})) (dp[i+1][r1+1][r2]+=dp[i][r1][r2])%=mod;
					if (!mp.count ({x+c,y+d})) (dp[i+1][r1][r2+1]+=dp[i][r1][r2])%=mod;
					if (!mp.count ({x+e,y+f})) (dp[i+1][r1][r2]+=dp[i][r1][r2])%=mod;
				}
			}
		}
		for (int i=0;i<=n;i++)
			for (int j=0;i+j<=n;j++)
				(ans+=dp[n][i][j])%=mod;
		cout<< ans;
		return 0;
	}
}
#undef i64
#undef pii

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}

D

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

#define i64 long long
namespace rab {
	const int mod=998244353;
	int n,m,k,s,t,x;
	i64 f[2010][2],g[2010][2];
	vector<int> e[2010];

	int main () {
		cin>> n>> m>> k>> s>> t>> x;
		for (int i=1,u,v;i<=m;i++) {
			cin>> u>> v;
			e[u].emplace_back (v);
			e[v].emplace_back (u);
		}
		for (int v: e[s]) {
			if (v^x) f[v][0]=1;
			else f[v][1]=1;
		}
		for (int i=2;i<=k;i++) {
			for (int u=1;u<=n;u++) {
				g[u][0]=f[u][0];
				g[u][1]=f[u][1];
				f[u][0]=f[u][1]=0;
			}
			for (int u=1;u<=n;u++) {
				for (int v: e[u]) {
					if (v^x) {
						(f[v][0]+=g[u][0])%=mod;
						(f[v][1]+=g[u][1])%=mod;
					} else {
						(f[v][0]+=g[u][1])%=mod;
						(f[v][1]+=g[u][0])%=mod;
					}
				}
			}
		}
		cout<< f[t][0];
		return 0;
	}
}
#undef i64

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}

F

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

#define i64 long long
namespace rab {
	const i64 inf=2e12;
	int n,k,x,a[510];
	i64 ans=-inf,f[510][510];
	deque<int> q;

	int main () {
		cin>> n>> k>> x;
		for (int i=1;i<=n;i++) cin>> a[i];
		if (x<n/k) {
			cout<< -1;
			return 0;
		}
		for (int i=0;i<=x;i++)
			for (int j=0;j<=n;j++)
				f[i][j]=-inf;
		f[0][0]=0;
		for (int l=1;l<=x;l++) {
			for (int i=l;i<=n;i++) {
				for (int j=max ({0,i-k});j<i;j++) {
					f[l][i]=max (f[l][i],f[l-1][j]+a[i]);
				}
			}
		}
		for (int i=n-k+1;i<=n;i++)
			ans=max (ans,f[x][i]);
		cout<< ans;
		return 0;
	}
}
#undef i64

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}

G

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

#define i64 long long
namespace rab {
	const i64 inf=5e13;
	int n,k,x,a[5010];
	i64 ans=-inf,f[5010][5010];
	deque<int> q;

	int main () {
		cin>> n>> k>> x;
		for (int i=1;i<=n;i++) cin>> a[i];
		if (x<n/k) {
			cout<< -1;
			return 0;
		}
		for (int i=0;i<=x;i++)
			for (int j=0;j<=n;j++)
				f[i][j]=-inf;
		f[0][0]=0;
		for (int l=1;l<=x;l++) {
			q.clear ();
			q.push_back (0);
			for (int i=1;i<=n;i++) {
				while (q.size ()&&f[l-1][q.back ()]<=f[l-1][i-1]) q.pop_back ();
				while (q.size ()&&q.front ()<max (0,i-k)) q.pop_front ();
				q.push_back (i-1);
				f[l][i]=f[l-1][q.front ()]+a[i];
			}
		}
		for (int i=n-k+1;i<=n;i++)
			ans=max (ans,f[x][i]);
		cout<< ans;
		return 0;
	}
}
#undef i64

int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	return rab::main ();
}
posted @ 2025-03-01 17:24  M_CI  阅读(14)  评论(0)    收藏  举报