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 国王的金库被一把神奇的锁封住了,只有解开谜题才能打开。
这个谜题涉及到两个神圣的数字 \(a\) 和 \(b\)。要打开金库,挑战者必须确定满足两个条件的最小密钥数字 \(m\):
- \(m\) 必须大于或等于 \(a\) 和 \(b\) 中的至少一个。
- 当 \(m\) 被 \(a\) 除时的余数必须等于 \(m\) 被 \(b\) 除时的余数。
只有找到 \(m\) 的最小正确值,才能打开金库并获得传说中的宝藏!
输入:
第一行包含一个整数 \(t\) $ (1 \leq t \leq 100) $,表示测试用例的数量。
每个测试用例由一行组成,包含两个整数 \(a\) 和 \(b\) $ (1 \leq a, b \leq 1000) $
输出:
对于每个测试用例,打印满足上述条件的最小整数 \(m\)。
样例:
2
4 6
472 896
12
52864
思路:
做法一:显然\(1000*1000*100\)的时间复杂度时可以暴力枚举检验的,但是这里用long long会TLE,用int就不会TLE了。
做法二:直接求lcm,最小公倍数。因为\(m=a*k1+c\)且\(m=b*k2+c\),两者连立,发现\(a*k1=b*k2\),显然他们两个得最小公倍数就为答案
#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\) (\(1 \leq t \leq 10^4\)),即测试用例的数量。
每个测试用例的第一行包含三个数字 \(n\), \(m\), \(k\) (\(1 \leq m, k \leq n \leq 2 \cdot 10^5\))。每个测试用例的第二行都包含一个二进制字符串 \(s\) 由 \(n\) 个字符 \(s_1s_2\ldots s_n\) 组成。(\(s_i \in \{0,1\}\) 对于 \(1 \leq i \leq n\))。
保证所有测试用例的 \(n\) 的总和不超过 \(2 \cdot 10^5\)。
输出:
对于每个测试用例,输出 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\) (\(1 \leq t \leq 10^4\)),表示测试用例的数量。
对于每个测试用例:
- 第一行包含两个整数 \(n\) 和 \(m\) (\(1 \leq n, m \leq 1000\)),代表迷宫中的行数和列数。
- 接下来的 \(n\) 行,每行包含一个由 \(m\) 个字符组成的字符串,表示迷宫中的方向。每个字符是以下之一:
- U (上)
- D (下)
- L (左)
- R (右)
- ? (未指定的方向)
保证所有测试用例的 \(n \cdot m\) 的总和不超过 \(10^6\)。
输出:
对于每个测试用例,打印一个整数,这是在为未指定的单元格分配方向后,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\) 座石柱,每座石柱由一个底座和顶部的 \(0\)、\(1\) 或 \(2\) 个铭文组成。
在每一步中,Darius 可以选择两座石柱 \(u\) 和 \(v\),使得这两座石柱上的铭文数量相差正好是 \(1\),并从铭文数量较多的石柱上转移一个铭文到另一座石柱上。保证至少有一座石柱上恰好有 \(1\) 个铭文。
由于美观是历史建筑的主要支柱,Darius 希望石柱的高度按铭文数量的非递减顺序排列。为了避免过度劳工人们的努力,他请求你计划一个最多 \(n\) 步的序列,以根据铭文的数量将石柱排列成非递减顺序。不要求 最小化移动次数。
输入:
第一行包含一个整数 \(t\) — 测试用例的数量。(\(1 \leq t \leq 3000\))
每个测试用例的第一行包含一个整数 \(n\) — 石柱的数量。(\(1 \leq n \leq 2 \cdot 10^5\))
第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\),其中 \(a_i \in \{0,1,2\}\) 表示第 \(i\) 列初始的铭文数量。保证至少有一列恰好有 \(1\) 个铭文。
保证所有测试用例的 \(n\) 的总和不超过 \(2 \cdot 10^5\)。
输出:
对于每个测试用例,输出一个整数 \(k\) — 用于对列进行排序的移动次数。(\(0 \leq k \leq n\))
然后,输出 \(k\) 行,每行包含两个整数 \(u_i\) 和 \(v_i\) (\(1 \leq u_i, v_i \leq n\)),代表第 \(i\) 次移动中涉及的列的索引。在每次移动中,必须满足 \(|a_{u_i} - a_{v_i}| = 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\) 个两两不同的排列 \(p_1, p_2, \ldots, p_k\),它们的大小为 \(n\),使得对于每一对索引 \(i\) 和 \(j\)(其中 \(1 \leq i, j \leq n\)),以下条件成立:
您的任务是帮助 Rayan,要么为给定的 \(n\) 和 \(k\) 提供一个有效的 \(k\) 谐波排列集合,要么确定这样的集合不存在。
我们称长度为 \(n\) 的序列为排列,如果它恰好包含从 \(1\) 到 \(n\) 的每个整数一次。
输入:
第一行包含一个整数 \(t\) (\(1 \leq t \leq 1000\)),表示测试用例的数量。
每个测试用例由两个整数 \(n\) 和 \(k\) 组成 (\(1 \leq n, k \leq 10^5\))。所有测试用例中 \(n \cdot k\) 的总和不超过 \(5 \cdot 10^5\)。
输出:
对于每个测试用例,如果存在一个 \(k\) 谐波排列集合,首先在第一行打印 "YES"。然后,打印 \(k\) 行,每行包含一个从 \(1\) 到 \(n\) 的整数的不同排列。
如果不存在这样的集合,请在第一行打印 "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/2*3)\)%\(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;
}
}
}

浙公网安备 33010602011771号