F Flower
题意简化:
有一朵初始有n片花瓣的花,Yuki会按轮次摘花瓣:每轮操作中,她先摘a片花瓣,之后再摘b片花瓣;若剩余花瓣不足,就把剩下的全部摘完。这个过程会持续到所有花瓣被摘完为止。
Yuki的规则是:当且仅当最后一片被摘下的花瓣属于某一轮中“先摘的a片”时,她会离开;否则,她会留下。
你的任务是:先摘下一部分花瓣(但不能全摘完,至少要留1片),使得Yuki最终会留下。请计算你需要摘下的最少花瓣数;如果无论你怎么先摘(不摘完)都无法让她留下,则输出“Sayonara”。
输入数据:
- 第一行输入一个整数t(1≤t≤100),表示测试用例的数量。
- 每个测试用例包含三个整数n、a、b(1≤n,a,b≤10⁹),分别表示初始花瓣数、每轮先摘的花瓣数、每轮后摘的花瓣数。
思路
分类讨论
- n<=a 必然无法留下
- 如果n>a and n<=a+b ,为了让她留下可以不摘,
- n%(a+b)>a,说明摘完有限论之后,剩下的比a多,那么不摘也可以让她留下
- 除去上述的情况,那摘取n%(a+b)个,就可以让她最后摘完b个花瓣
点击查看代码
//"现代汽车前瞻杯"2025牛客暑期多校训练营3
#include <bits/stdc++.h>
using namespace std;
using ll = long long;void solve() {ll n, a, b;cin >> n >> a >> b;if (n <= a) {cout << "Sayonara\n";} else if (n > a && n <= a + b || n % (a + b) > a) {cout << 0 << "\n";}else {cout << n % (a + b) << "\n";}
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int _ = 1;cin >> _;while (_--) {solve();}return 0;
}
D
Distant Control
你有n个机器人朋友,按顺序排成一排,标号从左到右为1, 2, ..., n。初始时,有些机器人是关闭的(状态为0),有些是开启的(状态为1)。
你的手机可以远程控机器人的电源状态,但有特定限制:存在一个常数a(1≤a≤n-1),你只能执行以下两种操作:
- 选择连续的a个全部处于开启状态的机器人,将它们全部关闭。
- 选择连续的a+1个全部处于关闭状态的机器人,将它们全部开启。
你的目标是:通过执行若干次操作(可以不执行任何操作),使最终处于开启状态的机器人数量尽可能多,求出这个最大可能值。
输入数据:
- 第一行输入一个整数t(1≤t≤4×10⁴),表示测试用例的数量。
- 每个测试用例包含两行:
- 第一行是两个整数n和a(2≤n≤2×10⁵,1≤a≤n-1),分别表示机器人总数和操作相关的常数。
- 第二行是一个长度为n的字符串s,由'0'和'1'组成,其中s[i]表示第i个机器人的初始状态('1'为开启,'0'为关闭)。
保证所有测试用例的n的总和不超过4×10⁵。
思路
可以思考到只要存在连续的a个开启的机器人,或者a+1个全部关闭的机器人,那么就可以通过不断操作使得全部开启
否则就是初始开的机器人数量
点击查看代码
//"现代汽车前瞻杯"2025牛客暑期多校训练营3
#include <bits/stdc++.h>
using namespace std;
using ll = long long;void solve() {ll n, a, cnt = 0;cin >> n >> a;string s;cin >> s;bool ok = false;for (ll i = 0; i < n; i++) {ll j;if (s[i] == '1') {for (j = i; j < i + a && j < n; j++) {if (s[j] != '1') {break;}}if (j - i == a) {ok = true;}} else {for (j = i; j < i + a + 1 && j < n; j++) {if (s[j] != '0') {break;}}if (j - i == a + 1) {ok = true;}}i = j - 1;}if (ok) {cout << n << "\n";} else {for (ll i = 0; i < n; i++) {if (s[i] == '1') {cnt++;}}cout << cnt << "\n";}
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int _ = 1;cin >> _;while (_--) {solve();}return 0;
}
J Jetton
题意简化:
Yuki和Ena进行回合制扑克游戏,初始时Yuki有x个筹码,Ena有y个筹码。每轮的胜负与支付规则如下:
- 若两人筹码数不同,筹码少的一方获胜;
- 若两人筹码数相同,Yuki获胜;
- 输的一方需向胜者支付“胜者当前拥有的筹码数”等量的筹码。
当任意一方的筹码变为0时,游戏立即结束。请判断游戏是否会在有限轮数内结束;若会,还需计算从开始到结束的总轮数。
输入数据:
- 第一行输入整数t(1≤t≤10⁵),表示测试用例数量。
- 每个测试用例输入两个整数x和y(1≤x,y≤10⁹),分别为Yuki和Ena的初始筹码数。
思路
暴力测试,目测应该不会超过100轮
点击查看代码
#include<bits/stdc++.h>using namespace std;
#define endl "\n"
const int maxn=110;
using ll=long long ;
const ll pr=1ll<<34;int cnt;void solve(){int x,y;cin>>x>>y;cnt=0;while(x && y){if(x<y){int t=x;x+=t;y-=t;}else if(x>y){int t=y;y+=t;x-=t;}else {int t=x;x+=t;y-=t;}++cnt;if(cnt>100){ cout<<-1<<'\n';return;}}cout<<cnt<<endl;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int T = 1;cin >> T;while(T--){solve();}return 0;
}
E Equal
题意简化:
Yuki 给你一个长度为 n
的正整数序列 a₁, a₂, ..., aₙ
,你可以任意次数执行以下两种操作:
- 操作1:选择两个位置
i
和j
(要求1≤i<j≤n
),再选一个正整数d
(要求d
能同时整除aᵢ
和aⱼ
,即d
是aᵢ
和aⱼ
的公约数);然后将aᵢ
更新为aᵢ/d
,aⱼ
更新为aⱼ/d
。 - 操作2:选择两个位置
i
和j
(要求1≤i<j≤n
),再选一个任意正整数d
;然后将aᵢ
更新为aᵢ×d
,aⱼ
更新为aⱼ×d
。
你的目标是判断:通过执行若干次上述操作后,能否让序列中所有元素都相等(即 a₁=a₂=...=aₙ
)。
输入数据:
- 第一行输入一个整数
t
(1≤t≤10⁵),表示测试用例的数量。 - 每个测试用例包含两行:
- 第一行是序列长度
n
(1≤n≤10⁶); - 第二行是
n
个正整数a₁, a₂, ..., aₙ
(1≤aᵢ≤5×10⁶),代表初始序列。
- 第一行是序列长度
- 保证所有测试用例的
n
之和不超过 2×10⁶(避免输入规模过大)。
思路
对于操作题的思考,可以考虑几种操作是否有神奇的组合达到化繁为简的效果
首先使得所有数相等,那么必然所有数的素因子个数相同
而通过两次操作,可以使得一个数*d,一个数不变,一个数/d,达到因数个数的转移,于是只有因数出现过偶数次或者n-因数次数是偶数就可以达到所有数相等
注意到n=2时直接判断两个数是否相同
点击查看代码
#include<bits/stdc++.h>using namespace std;
#define endl "\n"
using ll=long long ;
const ll pr=1ll<<34;
int cnt=0;
int n,m;
const int maxn=1e6;
bool isprime[maxn*5];
int s[maxn];
int top=0;
void ola(){isprime[1]=1;for(int i=2;i<=maxn*5;++i){if(!isprime[i])s[++top]=i;for(int j=1;j<=top && i*s[j]<=maxn*5;++j){isprime[i*s[j]]=1;if(i%s[j]==0) break; } }
// cout<<top<<endl;
}
void solve(){cin>>n;unordered_map<int,int>a; int w[3];for(int i=1;i<=n;++i){int x;cin>>x;if(i<=2) w[i]=x;for(int j=1;j<=top && x>=s[j];++j){while(x%s[j]==0 && x!=1){x/=s[j];a[s[j]]++;}if(isprime[x]==0){a[x]++;break;}}}if(n==1){cout<<"YES"<<endl;return ; }else if(n==2){if(w[1]!=w[2]) cout<<"NO"<<endl;else cout<<"YES"<<endl;return ;}for(auto [x,y]:a){//cout<<x<<" "<<y<<endl;y%=n;if((n-y)%2!=0 && y%2!=0){cout<<"NO"<<endl;return ;}}cout<<"YES"<<endl;return ;}
int main(){//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int T = 1;cin >> T;ola();while(T--){solve();}return 0;
}
A Ad-hoc Newbie
题意简化:
给定一个长度为 n
的正整数序列 f₁, f₂, ..., fₙ
(满足每个 fᵢ
都在 1 ≤ fᵢ ≤ i
范围内),需要你构造一个 n阶方阵A(即行数和列数均为 n
的矩阵),同时满足以下3个条件:
- 元素范围:矩阵中每个元素
Aᵢⱼ
(第i
行第j
列)都满足0 ≤ Aᵢⱼ ≤ n
; - 行mex条件:对每一行
i
,这一行所有元素的mex
值等于fᵢ
; - 列mex条件:对每一列
i
,这一列所有元素的mex
值也等于fᵢ
。
其中,mex
(最小未出现非负整数)的定义是:对于一个序列,mex
是最小的、没有在序列中出现过的非负整数(例如:序列 [0,1,3]
的 mex
是 2
,序列 [1,2]
的 mex
是 0
)。
题目保证:对任意合法的 f
序列,都存在满足条件的矩阵,你只需构造出任意一个即可。
输入数据:
- 第一行输入整数
t
(1 ≤ t ≤ 2×10⁴
),表示测试用例的数量; - 每个测试用例包含两行:
- 第一行是整数
n
(1 ≤ n ≤ 1414
),表示序列长度和矩阵的阶数; - 第二行是
n
个整数f₁, f₂, ..., fₙ
(1 ≤ fᵢ ≤ i
),表示给定的序列;
- 第一行是整数
- 保证所有测试用例的
n²
之和不超过2×10⁶
(避免矩阵规模过大)。
思路
构造题
对角线元素a[i][i]初始为 1,确保每行 / 列包含数字 1。
对于i < j的位置,a[i][j]和a[j][i]均设为i+1,保证矩阵对称(行i和列i的元素完全相同),后续只需保证行mex正确,列mex自然也正确。
当\(f_i = 1\)时:mex=1意味着 “0 必须出现,1 必须不出现”。原对角线a[i][i]是 1,修改为 0 后:
行i中包含 0(满足 “0 出现”);
行i中不再有 1(满足 “1 不出现”),因此mex为 1。
当\(f_i > 1\)时:mex=x意味着 “0,1,...,x-1 必须全部出现,x 必须不出现”。修改a[i][x-1]和a[x-1][i]为 0 后:
行i中包含 0(通过a[i][x-1] = 0);
行i中包含 1(对角线a[i][i]仍为 1);
行i中包含 2 到 x-1(由初始化时的j+1保证,j从 1 到 x-2 时,j+1恰好覆盖 2 到 x-1);
行i中不包含 x(通过初始化逻辑和x ≤ i的约束,可证明 x 不会出现在行i中)。
因此mex为 x,满足要求。
给出一种构造代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,a[1500][1500],n,x;
int main(){cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++){a[i][i]=1;for(int j=i+1;j<=n;j++){a[i][j]=a[j][i]=i+1;}}for(int i=1;i<=n;i++){cin>>x;if(x==1){a[i][i]=0;}else {a[i][x-1]=a[x-1][i]=0;}}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cout<<a[i][j]<<" ";} cout<<"\n";}} return 0;
}