Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2)题解记录(A~E)

比赛链接:https://codeforces.com/contest/2034
本场不是赛时也不是vp的,单纯赛后补的,现在看来怎么感觉比上次的edudiv2更简单些?

A. King Keykhosrow's Mystery

题面:
有一个关于睿智的国王 Keykhosrow 的故事,他拥有一个宏伟的宝库,里面装满了来自波斯帝国各地的宝藏。然而,为了防止盗窃和确保他的财富安全,Keykhosrow 国王的金库被一把神奇的锁封住了,只有解开谜题才能打开。
这个谜题涉及到两个神圣的数字 ab。要打开金库,挑战者必须确定满足两个条件的最小密钥数字 m

  • m 必须大于或等于 ab 中的至少一个。
  • ma 除时的余数必须等于 mb 除时的余数。

只有找到 m 的最小正确值,才能打开金库并获得传说中的宝藏!
输入:
第一行包含一个整数 t (1t100),表示测试用例的数量。

每个测试用例由一行组成,包含两个整数 ab (1a,b1000)
输出:
对于每个测试用例,打印满足上述条件的最小整数 m
样例:
2
4 6
472 896


12
52864
思路:
做法一:显然10001000100的时间复杂度时可以暴力枚举检验的,但是这里用long long会TLE,用int就不会TLE了。
做法二:直接求lcm,最小公倍数。因为m=ak1+cm=bk2+c,两者连立,发现ak1=bk2,显然他们两个得最小公倍数就为答案

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                    long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
	ll a,b;
	cin>>a>>b;
	ll u=gcd(a,b);
	cout<<a/u*b<<endl;
	}
	return 0;
}

B. Rakhsh's Revival

题面:
Rostam的忠实马 Rakhsh的日子好过。曾经强大而快速的 Rakhsh 随着时间的推移变得越来越虚弱,甚至难以移动。Rostam 担心,如果 Rakhsh 身体的太多部位同时失去力量,Rakhsh 可能会完全停止。为了让他的同伴继续前进,Rostam 决定一点一点地加强 Rakhsh,这样他身体的任何部分都不会太脆弱太久。

将 Rakhsh 的身体想象成一行点,由长度为 n 的二进制字符串 s 表示,其中每个 0 表示一个弱点,每个 1 表示一个强点。Rostam 的目标是确保没有连续 m 点的区间是完全弱的(全部是 0)。

幸运的是,Rostam 有一种叫做 Timar 的特殊能力,是他出生时从他的母亲 Rudabeh 那里继承的。使用 Timar,他可以选择任何长度 k 的段并立即加强所有段(将该段中的每个字符更改为 1)。挑战在于弄清楚 Rostam 需要使用 Timar 来保持 Rakhsh 移动的最少次数,确保没有连续的完全薄弱的长度 m 点。
输入:
第一行包含一个整数 t (1t104),即测试用例的数量。

每个测试用例的第一行包含三个数字 n, m, k (1m,kn2105)。每个测试用例的第二行都包含一个二进制字符串 sn 个字符 s1s2sn 组成。(si{0,1} 对于 1in)。

保证所有测试用例的 n 的总和不超过 2105
输出:
对于每个测试用例,输出 Rostam 需要使用 Timar 保持 Rakhsh 移动的最小次数,确保没有长度为 m 的连续完全弱点。
样例:
3
5 1 1
10101
5 2 1
10101
6 3 2
000000
———————
2
0
1
思路:最优方法应该是你在不符合的情况下放一个块使之符合答案,所以统计区间段,一旦区间段不符合,就以这个为左端点设置加强段

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                   long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}

int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n,m,k;
		cin>>n>>m>>k;
		string f;
		cin>>f;
		ll cnt=0;
		ll ans=0;
		ll dx=0;
		for(ll i=0;i<f.size();i++)
		{
			if(f[i]=='0'&&dx==0)
			{
				cnt++;
			}
			if(cnt==m)
			{
				cnt=0;
				dx=k;
				ans++;
			}
			if(f[i]=='1')
			cnt=0;
			dx--;
			dx=max(dx,(ll)0);
		}
		cout<<ans<<endl;
	}
	return 0;
}

C. Trapped in the Witch's Labyrinth

题面:
在 Rostam的第四个任务 中,来自 Shahnameh 的传奇英雄,一位老巫婆创造了一个魔法迷宫来困住他。迷宫是一个由 n 行和 m 列组成的矩形网格。迷宫中的每个单元格都指向一个特定的方向:上、下、左或右。巫婆施法让 Rostam 每当他处于一个单元格时,他将移动到由该单元格指示的下一个单元格。

如果 Rostam 最终走出迷宫,他将从巫婆的咒语中解脱出来并击败她。然而,如果他永远被困在迷宫中,他将永远无法逃脱。

巫婆还没有确定所有单元格的方向。她想要以一种方式分配方向给未指定的单元格,使得 Rostam 将永远被困住的起始单元格数量最大化。您的任务是找出使 Rostam 被困的起始单元格的最大数量。
输入:
第一行的输入包含一个整数 t (1t104),表示测试用例的数量。

对于每个测试用例:

  • 第一行包含两个整数 nm (1n,m1000),代表迷宫中的行数和列数。
  • 接下来的 n 行,每行包含一个由 m 个字符组成的字符串,表示迷宫中的方向。每个字符是以下之一:
    • U (上)
    • D (下)
    • L (左)
    • R (右)
    • ? (未指定的方向)

保证所有测试用例的 nm 的总和不超过 106
输出:
对于每个测试用例,打印一个整数,这是在为未指定的单元格分配方向后,Rostam将永远被困住的最大起始单元格数量。
样例:
3
3 3
UUU
L?R
DDD
2 3
???
???
3 3
?U?
R?L
RDL
————
0
6
5
思路:思考不合法方案。对于外围一圈,如果箭头只想外面必定不符合,所以写个dfs对于这些不符合的点进行深搜,这个深搜每次去看周围有没有指向自己的箭头,有就继续搜并打上标记。如何解决?,可以发现对于每个不合法的点可以对于他四周进行次数标记,如果一个?被打过4次标记,他就什么方向都不行,也就是不合法点。所以最后遍历一遍,对于?统计没标记过四次的,对于箭头统计没记过的

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                   long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
string f[2500];
bool vis[1005][1005];
ll fk[1005][1005];
ll u[5]={0,0,1,0,-1};
ll d[5]={0,1,0,-1,0};
char g[5]={'0','L','U','R','D'};
ll n,m;
void dfs(ll x,ll y)
{
	vis[x][y]=1;
	for(ll i=1;i<=4;i++)
	{
		ll nx=x+u[i];
		ll ny=y+d[i];
		fk[nx][ny]++;
		if(vis[nx][ny]||nx<1||ny<1||nx>n||ny>m||g[i]!=f[nx][ny])
		continue;
		dfs(nx,ny);
	}
}
bool vi[10005][1005];
ll ck(ll x,ll y)
{
	if(vi[x][y])return 0;
	vi[x][y]=1;
	if(f[x][y]=='?')
	{
		for(ll i=1;i<=4;i++)
		{
			ll nx=x+u[i];
			ll ny=y+d[i];
			if(nx<1||ny<1||nx>n||ny>m)
			fk[x][y]++;
		}
	}
	if(f[x][y]=='U')
	{
		if(x-1<1)
		return 1;
	}
	if(f[x][y]=='D')
	{
	if(x+1>n)
	return 1;
	}
	if(f[x][y]=='R'&&y+1>m)
	return 1;
	if(f[x][y]=='L'&&y-1<1)
	return 1;

	return 0;
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(ll i=1;i<=n;i++)
		{
			cin>>f[i];
			f[i]='0'+f[i];
		}
		for(ll i=0;i<=n;i++)
		{
			for(ll j=0;j<=m;j++)vis[i][j]=fk[i][j]=vi[i][j]=0;
		}
		for(ll j=2;j<=m-1;j++)
		{
			fk[1][j]++;
			if(f[1][j]=='U')
			{
				dfs(1,j);
			}
		}
		//fk[1][1]+=2,fk[1][m]+=2;
		if(ck(1,1))dfs(1,1);
	  //  cout<<fk[1][1]<<endl;
		if(ck(1,m))dfs(1,m);
		for(ll j=2;j<=n-1;j++)
		{
			fk[j][m]++;
			if(f[j][m]=='R')
			dfs(j,m);
		}
	//	fk[n][m]+=2;
		if(ck(n,m))dfs(n,m);
		for(ll j=2;j<=m-1;j++)
		{
			fk[n][j]++;
			if(f[n][j]=='D')
			dfs(n,j);
		}
		//fk[n][1]+=2;
		if(ck(n,1))dfs(n,1);
		for(ll j=2;j<=n-1;j++)
		{
			fk[j][1]++;
			if(f[j][1]=='L')
			dfs(j,1);
		}
		ll ans=0;
		for(ll i=1;i<=n;i++)
		{
			for(ll j=1;j<=m;j++)
			{
				if(vis[i][j])continue;
				if(f[i][j]=='?'&&fk[i][j]<4)ans++;
				if(f[i][j]!='?')ans++;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

D. Darius' Wisdom

题面:
大流士 Darius 正在建造 n 座石柱,每座石柱由一个底座和顶部的 012 个铭文组成。

在每一步中,Darius 可以选择两座石柱 uv,使得这两座石柱上的铭文数量相差正好是 1,并从铭文数量较多的石柱上转移一个铭文到另一座石柱上。保证至少有一座石柱上恰好有 1 个铭文。
由于美观是历史建筑的主要支柱,Darius 希望石柱的高度按铭文数量的非递减顺序排列。为了避免过度劳工人们的努力,他请求你计划一个最多 n 步的序列,以根据铭文的数量将石柱排列成非递减顺序。不要求 最小化移动次数。
输入:
第一行包含一个整数 t — 测试用例的数量。(1t3000)

每个测试用例的第一行包含一个整数 n — 石柱的数量。(1n2105)

第二行包含 n 个整数 a1,a2,,an,其中 ai{0,1,2} 表示第 i 列初始的铭文数量。保证至少有一列恰好有 1 个铭文。

保证所有测试用例的 n 的总和不超过 2105
输出:

对于每个测试用例,输出一个整数 k — 用于对列进行排序的移动次数。(0kn)

然后,输出 k 行,每行包含两个整数 uivi (1ui,vin),代表第 i 次移动中涉及的列的索引。在每次移动中,必须满足 |auiavi|=1,并且一个铭文从铭文数量较多的列转移到另一列。

可以证明,在给定的约束条件下,总存在一个有效的解决方案。
样例:
3
4
0 2 0 1
3
1 2 0
6
0 1 1 2 2 2
————————————
2
2 4
2 3
2
3 1
2 3
0
思路:这题的代码量比上题少多了,先统计0,1的数量,然后开三个set,分别储存0,1,2的位置,从前往后遍历,
如果这个位置得是0,但是是1,那就把最远得0和现在得1交换位置。顺便更新下set容器,如果是2,就先把此时的2和最远的1交换,然后再把现在的1和最远的0交换。
如果这个位置得是1,但是是2,那就把最远的1和现在的2交换下位置。
如果这个位置得是2时,早以解决,直接break

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
//#include<bits/stdc++.h>
#include <unordered_map>
#define ll                               long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
// const ll p=rnd()%mod;
const ll maxn=2e5+15;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[250000];
ll b[5];
set<ll>q[4];
vector<pair<ll,ll>>g;
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		g.clear();
		q[1].clear();
		q[2].clear();
		q[0].clear();
		b[0]=b[1]=b[2]=0;
		for(ll i=1;i<=n;i++)
		{
		cin>>a[i];
		b[a[i]]++;
		if(a[i]==1)
		q[1].insert(i);
		else if(a[i]==2)
		q[2].insert(i);
		else q[0].insert(i);
		}
		for(ll i=1;i<=n;i++)
		{
			if(b[0]>0)
			{
				if(a[i]==0)b[0]--;
				else if(a[i]==1)
				{
					auto u=q[0].rbegin();
					q[0].insert(i);
					q[1].erase(i);
					q[1].insert(*u);
					swap(a[*u],a[i]);
					g.push_back({i,*u});
						q[0].erase(*u);
					b[0]--;
				}
				else 
				{
					auto u=q[1].rbegin();
						swap(a[*u],a[i]);
					g.push_back({i,*u});
					q[2].insert(*u);
					q[1].erase(*u);
					q[1].insert(i);
					q[2].erase(i);
					 u=q[0].rbegin();
					 	swap(a[*u],a[i]);
					g.push_back({i,*u});
					q[0].insert(i);
					q[1].erase(i);
					q[1].insert(*u);
					q[0].erase(*u);
					b[0]--;
				}
			}
			else if(b[1]>0)
			{
				if(a[i]==1)b[1]--;
				else 
				{
					auto u=q[1].rbegin();
					q[2].insert(*u);
					q[1].insert(i);
					q[2].erase(i);
					swap(a[*u],a[i]);
					g.push_back({i,*u});
					b[1]--;
					q[1].erase(*u);
				}
			}
			else break;
		}
		cout<<g.size()<<endl;
		for(auto x:g)
		{
			cout<<x.first<<" "<<x.second<<endl;
		}
	}
}

E. Permutations Harmony

题面:
Rayan 想向 Reyhaneh 赠送一份礼物,以赢得她的心。但是,Reyhaneh 很特别,并且只接受一组 k 谐波排列。

我们定义一个 k 谐波排列集合为一组 k两两不同的排列 p1,p2,,pk,它们的大小为 n,使得对于每一对索引 ij(其中 1i,jn),以下条件成立:

p1[i]+p2[i]++pk[i]=p1[j]+p2[j]++pk[j]

您的任务是帮助 Rayan,要么为给定的 nk 提供一个有效的 k 谐波排列集合,要么确定这样的集合不存在。

我们称长度为 n 的序列为排列,如果它恰好包含从 1n 的每个整数一次。
输入:

第一行包含一个整数 t (1t1000),表示测试用例的数量。

每个测试用例由两个整数 nk 组成 (1n,k105)。所有测试用例中 nk 的总和不超过 5105
输出:

对于每个测试用例,如果存在一个 k 谐波排列集合,首先在第一行打印 "YES"。然后,打印 k 行,每行包含一个从 1n 的整数的不同排列。

如果不存在这样的集合,请在第一行打印 "NO"。

在任何情况下,您都可以输出 “YES” 和 “NO”(例如,字符串 “yEs”、“yes” 和 “Yes” 将被识别为肯定响应)。

如果有多个答案,您可以输出其中任何一个。
样例:
4
3 3
4 2
5 1
3 2


YES
1 2 3
2 3 1
3 1 2
YES
1 2 3 4
4 3 2 1
NO
YES
1 2 3
3 2 1
思路:首先特判k=1时的情况。然后发现一个n序列的最多不同排序数为n!,如果k大于这个直接NO。
其实一个排列和另一个排列每列加起来等于n+1具有对称性,如:1 2 3 ,3 2 1,他们各占n!/2,如果k等于偶数,直接使用next_permutation(),全排列函数直接输出此时序列和对称序列,不要怕会重复,再重复之前,一定可以输出完答案的,到时候break就行了
如果k为奇数,首先得考虑((1+n)n/23)%n得等于0,因为如果这个不满足就一定不能构造出,如果这个满足了,我就只要先构造出三个符合条件的排列(这个可以看我代码,但是可以手画下,可以发现只有n为奇数时此时才有解),然后剩下的利用对称性就好了,要注意构造出的那三,相当于减少了全排列6种情况,记得再讨论下此时有没解。随后利用hash+map去记录前三个排列的hash值,然后使用next_permutation先检验此时排列和对称排列的hash值有没重复就好了,一个都没重复才算合理输出。

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
//#include<bits/stdc++.h>
#include <unordered_map>
#define ll                               long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9+7;
const ll p=rnd()%mod;
const ll maxn=2e5+15;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
bool vis[250000];
ll a[250000];
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n,k;
		cin>>n>>k;
		for(ll i=1;i<=n;i++)
		{
			a[i]=i;
		}
		if(n==1&&k==1)
		{
			cout<<"YES"<<endl;
			cout<<1<<endl;
			continue;
		}
		if(k==1)
		{
			cout<<"NO"<<endl;
			continue;
		}
		ll cnt=1;
		ll pd=0;
		for(ll j=1;j<=n;j++)
		{
			cnt*=j;
			if(cnt>=k)
			{
				pd=1;
				break;
			}
		}
		if(pd==0)
		{
			cout<<"NO"<<endl;
			continue;
		}
		if(k%2==0)
		{
			cout<<"YES"<<endl;
			do
			{
				k-=2;
				for(ll i=1;i<=n;i++)
				cout<<a[i]<<" ";
				cout<<endl;
				for(ll i=1;i<=n;i++)
				cout<<n+1-a[i]<<" ";
				cout<<endl;
				if(k==0)
				break;
			} while (next_permutation(a+1,a+1+n));
		}
		else 
		{
			ll d=1;
			ll pd=0;
			for(ll i=1;i<=n;i++)
			{
				d*=i;
				if(d-6>=k-3)
				pd=1;
			}
			if(pd==0)
			{
				cout<<"NO"<<endl;
				continue;
			}
			ll u=(1+n)*n/2*3;
			map<ll,bool>mp;
			if(u%n==0)
			{
				cout<<"YES"<<endl;
				ll ha=0;
				for(ll i=1;i<=n;i++)
				{
					cout<<i<<" ";
					ha=((ha*p)%mod+i)%mod;
				}
				cout<<endl;
				mp[ha]=1;
				ha=0;
				for(ll i=(n+1)/2;i<=n;i++)
				{
					cout<<i<<" ";
					ha=((ha*p)%mod+i)%mod;
				}
				for(ll i=1;i<=(n+1)/2-1;i++)
				{
					cout<<i<<" ";
					ha=((ha*p)%mod+i)%mod;
				}
				cout<<endl;
				mp[ha]=1;
				ha=0;
				for(ll i=n;i>=1;i-=2)
				cout<<i<<" ",ha=((ha*p)%mod+i)%mod;
				for(ll i=n-1;i>=1;i-=2)
				cout<<i<<" ",ha=((ha*p)%mod+i)%mod;
				mp[ha]=1;
				cout<<endl;
				k-=3;
				if(k>0)
				{
				do
				{
					ll ha1=0,ha2=0;
					for(ll i=1;i<=n;i++)
					ha1=(ha1*p%mod+a[i])%mod;
					for(ll i=1;i<=n;i++)
					ha2=(ha2*p%mod+n+1-a[i])%mod;
					if(mp[ha1]==0&&mp[ha2]==0)
					{
						k-=2;
						for(ll i=1;i<=n;i++)
						cout<<a[i]<<" ";
						cout<<endl;
						for(ll i=1;i<=n;i++)
						cout<<n+1-a[i]<<" ";
						cout<<endl;
					}
					if(k==0)
					break;
				} while (next_permutation(a+1,a+1+n));
				}
			}
			else 
			cout<<"NO"<<endl;
		}
	}
}
posted @   长皆  阅读(54)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示