比赛链接:https://codeforc.es/contest/1716

A了两道题 A和B,速度还可以,但是CD态度太大一个也没做出来。

A题:给出一个数n,从0点开始到n点,每次只能走2步或3步,也可以回退。求最少多少次可以走到n点。

很简单,我们优先考虑3,如果是3的倍数可以直接/3过去,否则我们需要回退一个3这一个操作我们并不需要浪费一次,然后用两个2到达终点。

code:


#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)

int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		int sum = 0;
		sum = n/3;
		if(sum*3<n)
		{
			sum++;
		}
		if(n==1)	sum=2;
		cout<<sum<<endl;
	}
}


B题:大意是给出一个n,输出一些长度为n的数据我们定义为ki,对于任意一个ki,我们可以交换任意两个位置的元素,如果元素被改变,我们令固定性=n--改变的数量。这k组数组,我们要求严格固定性ki>ki+1。输出最多可以组数,存在多个输出任意。

解决方法:我们每次交换两个,最多可以使得严格意义执行n次,即第一次固定性为n,然后n-2,n-3一直到0

code:


#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
vector<int>ve;
int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		ve.clear();
		int n;
		cin>>n;
		cout<<n<<endl;
		for(int i=1;i<=n;i++)
			ve.push_back(i);
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<ve.size();j++)
				cout<<ve[j]<<' ';
			cout<<endl;
			swap(ve[i],ve[i+1]) ;
		}
	}
}
C题:大意是有2*m个格子,每个格子有个开放时间,只有在开放时间之后才能进入这个格子。机器人在0,0位置,需要求出最少多长时间可以走完所有格子 “每个格子只能走一遍” href="http://www.cxb520.cn/content/uploadfile/202208/71c01659771187.jpg" target="_blank">QQ图片20220806153256.jpg

通过观察我们可以发现,行走方式只有  波浪行 和 绕行。

我们首先可以求出每个位置所需的最短时间,  影响因子有   对应另一行的时间+1,波浪行和绕行,其中一个最大值。

我们枚举所有的列,对于列中的每一行中的位置,我们可以通过绕行到达或者之前我们计算的时间到达。这样在这个过程当中,我们可以更新波浪行,然后对于我们需要求的当前列中的元素,我们看看波浪行和存储的可达到时间哪个小。由此我们可以知道在哪个位置改为波浪行所有时间更少。总共计算m列,我们可以在一个最佳位置中选出最少时间。

code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
const int nn = 2e5+10;
int a[3][nn];
int dp[3][nn]; 
int m;
int main()
{
	//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>m;
		for(int i=0;i<2;i++)
			for(int j=0;j<m;j++)
				cin>>a[i][j];
		a[0][0] = -1;
		dp[0][m] = 0,dp[1][m] = 0;
		for(int j=m-1;j>=0;j--)
			for(int i=0;i<2;i++)
				dp[i][j] = max(max(a[1-i][j]+1,a[i][j]+2*(m-j)),dp[i][j+1]+1);
		//a[1-i][j]+1  是从上进入下 或 从下进入上的时间
		//a[i][j]+2*(m-j) 是上下绕行
		//dp[i][j+1]+1 是由身后的位置转移过来	 
		int cur = 0;
		int ans = 0x3f3f3f3f;
		for(int i=0;i<m;i++)
		{
			int k = i&1;
			ans = min(ans,max(cur,dp[k][i]));//让ans更新至  当前走过的时间和走到ki位置所需的等待时间的最大值 
			cur = max(cur,a[k][i]+2*(m-i));//cur更新至两个绕行路径的最大时间 
			cur = max(cur,a[1-k][i]+2*(m-i)-1);
		}
		cout<<ans<<endl;			
	}
}

D题:大意是给出一个数n,给出一个初始间距k。询问0 - x(1<=x<=n),询问有多少种方式可以到达。对于当前数,它可以到达某个数-当前数的值是k的倍数的数,在到达一次后,k值会往上+1,最后我们需要正好到达  x。求出到达每一个x的方式数量。

我们定义f[i]为m到达当前i的数量,这个值等于之前m到达i的量的总和
s[i]为之前所有m到达i量的总和,上一个m可以通过i-m获取。
通过观察,我们可以试着列出所有的m 当累加<=n时。依次来更新所有f[i],通过每一次的f[i]由此更新所有ans。

code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)

const int nn = 400005;
const int mod = 998244353;

int s[nn],f[nn],ans[nn];
int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n,m;
	cin>>n>>m;
	f[0] = 1;
	int wc = 0;
	while(m<=n&&wc<=n){//当间隔依次是  1 2 3 ...  s总和<=n  时,能否到达某个i点 
		for(int i=0;i<=n;i++){
			int tmp;//上一个阶段前缀值的和 
			if(i-m>=0)	tmp = s[i-m];
			else tmp = 0;
			s[i] = (tmp+f[i])%mod;//这里的fi 是m-1阶段  到达目标i的可能性数  
			f[i] = tmp;//si的前缀和等于 si-m  +  本阶段m  ,所以能够到达 
			ans[i] = (ans[i]+f[i])%mod;
		}
		wc+=m++;
	}
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<' ';
}