寒假组队训练第一场2025.1.13

本次vpICPC昆明区域赛,本次vp一共做了五道题,C题后面补的
比赛地址:https://codeforces.com/gym/105588

C.coin

题面:
政府决定削减海军预算,将节省下来的金币直接分给海盗。这招比海军消灭的海盗还要多。

——煮鸡

海盗们刚刚夺取了一枚巨大的金币!

为了确定这枚金币的归属,他们决定用以下方法来选择主人:

设当前剩余海盗的数量为 \(n\)。海盗们排成一队,位于位置 \(1, 1+k, 1+2k, \dots, 1+(\lceil\frac{n}{k}\rceil - 1) k\) 的海盗被清除。这个操作不断重复,直到只剩下一名海盗。最后剩下的海盗将获得金币。

查理是海盗中最聪明的人。他想知道他应该最初站在哪个位置,才能成为最后一个剩下的海盗,赢得金币。
输入:
每个测试文件包含多个测试用例。第一行包含测试用例的数量 \(T\)\(1 \leq T \leq 100\))。测试用例的描述紧随其后。

每个测试用例的第一行包含两个整数 \(n\)\(k\)\(2 \leq n, k \leq 10^{12}\)),分别表示最初的海盗数量和用于清除的参数。

对于每个测试文件,保证所有测试用例中 \(n\) 的总和不超过 \(10^{12}\),所有测试用例中 \(k\) 的总和不超过 \(10^{12}\)
输出:
对于每个测试用例,在新行上输出一个整数,表示最终将在初始队列中收到金币的海盗的位置。
样例:
4
6 2
8 3
10000 2
1919810 114514
——————————————————
4
8
8192
1919805
思路:队友想了很久都没做出来,这道题是补的,后面由队友补充,思路就不写了,codeforces有中文题解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int f[1000500]={0};
ll up(ll n,ll k){
	if(n/k*k==n){
		return n/k;
	}else{
		return n/k+1ll;
	}
}
void solve(){
	ll n=0,k=0;scanf("%lld %lld",&n,&k);
	if(n<=k){
		printf("%lld",n);
		return;
	}
	if(k==2){
		ll ans=1;
		while(n>1){
			n/=2;
			ans*=2;
		}	
		printf("%lld",ans);
	}else if(k<sqrt(n)){
		ll nn=n;
		ll r=0;
		while(nn>1){
			nn-=((nn-1)/k+1);
			r++;
		}
		ll a=1;
		while(r){
			a+=up(a,k-1);
			r--;
		}
		printf("%lld",a);
	}else{
		ll a=n;
		ll r=0;
		ll now=up(n,k);
		while(now>=1){
			if(now==1){
				r+=(a-1);
				break;
			}
			ll tmp=up((a-(now-1)*k),now);
			r+=tmp;
			a-=(tmp*now);
			now--;
		}
		a=1;
		now=1;
		while(r){
			ll tmp=up((now*(k-1)-a+1),now);
			tmp=min(r,tmp);
			r-=tmp;
			a+=tmp*up(a,k-1);
			now++;
		}
		printf("%lld",a);
	}

}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
		printf("\n");
		
	}
	return 0;
}

G.GCD

题面:
有没有人明白为什么很多出题人觉得把一个与最大公约数(GCD)相关的问题放在第 G 题很有趣呢?

——红烧鸡

给定两个整数 \(a\)\(b\),在每一轮你可以执行以下两种操作之一:

  • 如果 \(a > 0\),则将 \(a\) 的值减少 \(\gcd(a, b)\)
  • 如果 \(b > 0\),则将 \(b\) 的值减少 \(\gcd(a, b)\)

Grace 想知道使 \(a\)\(b\) 都变为 \(0\) 所需的最少轮数。

\(^{\dagger}\) \(\gcd(x, y)\) 表示 \(x\)\(y\) 的最大公约数。例如,\(\gcd(6, 8) = 2\)\(\gcd(7, 5) = 1\)\(\gcd(x, 0)\)\(\gcd(0, x)\) 的值定义为 \(x\)
输入:
每个测试文件包含多个测试用例。第一行包含测试用例的数量 \(T\)\(1 \leq T \leq 1000\))。测试用例的描述紧随其后。

每个测试用例由一行组成,包含两个整数 \(a\)\(b\)\(1 \leq a \leq b, a \leq 5000, b \leq 10^{18}\))。

对于每个测试文件,保证所有测试用例中 \(a\) 的总和不超过 \(10^4\)
输出:
对于每个测试用例,输出一个整数,表示使 \(a\)\(b\) 都变为 \(0\) 所需的最少轮数。
样例:
3
3 4
12 20
114 514
——————————
3
4
6
思路:其实原本是写了个dp的,但是wa2了,然后队友过来写了个bfs对拍,对了几个大数字后发现,其实深度不会特别大,遂用对拍代码直接过了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){
	if(b==0) return a;
	else return gcd(b,a%b);
}
struct node{
	ll	x,y,step;
};
void solve(){
	ll x,y;
	cin>>x>>y;
	queue<node>q;
	q.push({x,y,0ll});
	ll ansx,ansy,ans;
	while(!q.empty()){
		node now=q.front();
		q.pop();
		if(now.x==0||now.y==0){
//			cout<<"x:"<<now.x<<"y:"<<now.y<<"step:"<<now.step<<"\n";
			ansx=now.x,ansy=now.y;
			ans=now.step;
			break;
		}
		q.push({now.x-gcd(now.x,now.y),now.y,now.step+1});
		q.push({now.x,now.y-gcd(now.x,now.y),now.step+1});
	}
	if(ansx==0&&ansy==0){
		printf("%lld",ans);
	}else{
		printf("%lld",ans+1);
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
		printf("\n");
	}
	return 0;
}

H.Horizon Scanning

题面:
冷笑话:雷达是一个回文词。

解释:这其实是一个冷知识,而不是冷笑话。这两个概念之间的混淆让它变得有趣。

——豆腐鸡

Hana 最近需要开发一个雷达系统,以监控她管理的群岛上的异常活动。

海洋中有 \(n\) 个岛屿,第 \(i\) 个岛屿位于坐标 \((x_i, y_i)\),可以将其视为平面上的一个点。假设雷达的扫描角度范围为 \(\alpha\)。当雷达旋转到角度 \(\theta\) 时,它可以监测位于角度范围 \([\theta - \frac{\alpha}{2}, \theta + \frac{\alpha}{2}]\) 内的所有岛屿。

Hana 目前资金紧张,所以她希望尽量降低建造雷达的成本。她想知道,当雷达放置在原点 \((0,0)\) 时,最小的扫描角度 \(\alpha\) 应该是多少,以确保对于任何角度 \(\theta\),雷达都能监测到至少 \(k\) 个岛屿。
输入:
每个测试文件包含多个测试用例。第一行包含测试用例的数量 \(T\)\(1 \leq T \leq 10^4\))。测试用例的描述紧随其后。

每个测试用例的第一行包含两个整数 \(n\)\(k\)\(1 \leq k \leq n \leq 2 \times 10^5\)),分别表示岛屿的总数和雷达在任何给定时间必须监测的最少岛屿数。

接下来的 \(n\) 行每行包含两个整数 \(x_i\)\(y_i\)\(|x_i|, |y_i| \leq 10^9\)),表示一个岛屿的位置。保证任意两个岛屿的坐标不同,且没有一个岛屿位于原点。

对于每个测试文件,保证所有测试用例中 \(n\) 的总和不超过 \(2 \times 10^5\)
输出:
对于每个测试用例,输出一个十进制分数,表示最小的雷达扫描角度(以弧度为单位)。

如果答案的绝对误差或相对误差不超过 \(10^{-6}\),则认为你的答案是正确的。

正式地说,设你的答案为 \(a\),评委的答案为 \(b\)。只有当 \(\frac{|a - b|}{\max{(1, |b|)}} \leq 10^{-6}\) 时,你的答案才被接受。
样例:
5
1 1
0 1
8 2
1 0
1 1
0 1
-1 1
-1 0
-1 -1
0 -1
1 -1
4 2
-1 1
0 1
0 2
1 1
4 2
-1000000000 0
-998244353 1
998244353 1
1000000000 0
3 1
0 1
0 2
0 -1
——————————————
6.2831853072
1.5707963268
5.4977871438
3.1415926546
3.1415926536
思路:队友写的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1e6+5;
const double pi=acos(-1);
struct Point {
  ll x, y;
  double ang;
  Point operator-(const Point& p) const { return {x - p.x, y - p.y, 0}; }
} p[MAX];

double dis(Point p1, Point p2) {
  return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

bool cmp(Point p1, Point p2) {
  if (p1.ang == p2.ang) {
    return dis(p1, p[0]) < dis(p2, p[0]);
  }
  return p1.ang < p2.ang;
}

ll cross(Point p1, Point p2) { 
	return p1.x * p2.y - p1.y * p2.x;//叉乘
}
void solve(){
//	printf("%.12lf",pi);
	p[0].x=0;p[0].y=0;
	int n,k;
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++){
		ll x,y;       
		scanf("%lld %lld",&p[i].x,&p[i].y);
	}
  	for (int i = 1; i <= n; i++ ) {
    	p[i].ang = atan2(p[i].y - 0, p[i].x - 0);
  	}
  	sort(p+1, p+n+1,cmp);
  	if(n==1||n==k){
  		printf("%.9lf",2*pi);
  		return ;
	}
  	double jd=0;
  	for(int i=2;i<=n;i++){
  		if(p[i].ang-p[i-1].ang<-0.000001){
  			jd+=p[i].ang-p[i-1].ang+2*pi;	
		}else{
			jd+=p[i].ang-p[i-1].ang;
		}
	}
	if(fabs(jd)<0.00001){
		printf("%.9lf",2*pi);
		return ;
	}
  	double ans=0;
  	double now=0;
	for(int i=2;i<=k+1;i++){
		double tmp=p[i%(n)+(n*(i==n))].ang-p[i-1].ang;
		if(tmp<-0.000001){
			tmp+=2*pi;
		}
		now+=tmp;
	}
	ans=max(ans,now);
	for(int i=2;i<=n;i++){//以..为头
		double tmp=p[i%(n)+(n*(i==n))].ang-p[i-1].ang;
		if(tmp<-0.000001){
			tmp+=2*pi;
		}
		now-=tmp;
		tmp=p[(i+k)%(n)+(n*((i+k)==n))].ang-p[(i+k-1)%(n)+(n*(i+k-1==n))].ang;
		if(tmp<-0.000001){
			tmp+=2*pi;
		}
		now+=tmp;
		ans=max(ans,now);
	}
	printf("%.9lf",ans);	
}
int main(){
	int t=1;
	scanf("%d",&t);
	while(t--){
		solve();
		printf("\n");
	}
	return 0;
}

J.Just another Sorting Problem

题面:
根据问题陈述,Bob是活得更久的那个人。
—Hotpot-chicken

Jessica是排序算法的大师,精通选择排序、插入排序、冒泡排序等许多算法。因此,她决定举办一场排序比赛。

比赛在一个长度为\(n\)的排列\(p\)上进行,有两名参赛者:Alice和Bob。两名选手轮流进行操作,谁先操作由抛硬币决定。如果在任何选手的回合结束后序列呈升序排列,Alice立即获胜。如果Alice在有限的回合内无法获胜,则认为Bob获胜。

在Alice的回合,她可以选择排列中的任意两个位置\(i,j\)\(i \neq j, 1 \leq i,j \leq n\))并交换\(p_i\)\(p_j\)。在Bob的回合,他可以选择两个相邻的位置\(i,i+1\)\(1 \leq i < n\))并交换\(p_i\)\(p_{i+1}\)。两名选手都不允许跳过他们的回合。

给定排列\(p\)和先操作的选手的名字,确定如果双方都采取最优策略,谁将赢得比赛。

\(^{\dagger}\) 长度为\(n\)的排列是一个由\(n\)个不同的整数组成的数组,这些整数从1到\(n\),顺序任意。例如,\([2,3,1,5,4]\)是一个排列,但\([1,2,2]\)不是排列(数组中2出现了两次),\([1,3,4]\)也不是排列(\(n=3\)但数组中有一个4)。
输入:
每个测试文件包含多个测试用例。第一行包含测试用例的数量\(T\)\(1 \leq T \leq 10^4\))。测试用例的描述如下。

每个测试用例的第一行包含一个整数\(n\)\(2 \leq n \leq 10^5\))和一个字符串\(s\)\(s \in \{\)Alice, Bob\(\}\)),表示排列的长度和先操作的选手的名字。

第二行包含\(n\)个整数\(p_1, p_2, \cdots, p_n\)\(1 \leq p_i \leq n\)),表示排列\(p\)。保证至少有一个位置\(i\)使得\(p_i \neq i\)

对于每个测试文件,保证所有测试用例中所有\(n\)的总和不超过\(10^5\)
输出:
对于每个测试用例,输出一行包含获胜者的名字。如果Alice获胜,打印"Alice";否则,打印"Bob"。
样例:
3
2 Alice
2 1
3 Bob
1 3 2
10 Bob
1 2 3 4 5 6 7 8 10 9
————————————————————
Alice
Bob
Bob
思路:发现n=2,Alice必赢。n=3,如果Alice先手,想赢只能一开始刚好只有两个地方错了,否则如果出现一个错误,Bob可以一直维护他。如果Bob先手,如果一开始刚好全对或者全错就一定Alice赢,否则Bob赢。当n>=4,如果只有2个地方不对且Alice先手或者全对且Bob先手这两种情况,Alice赢,否则就是Bob赢。只要出现一个错误,Bob就可以一直维护这个错误。

#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<functional>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//#include<bits/stdc++.h>
#include <unordered_map>
#define ll            long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
//using namespace __gnu_pbds;
mt19937 rnd(time(0));
const ll p = 998244353;
const ll mod = 998244353;
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);
}
struct s
{
	ll l, r;
	bool operator<(const s& a)const
	{
		return l < a.l;
	}
};
ll a[250000];
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		string f;
		cin>>n>>f;
		ll cnt=0;
		for(ll i=1;i<=n;i++)
		{
			cin>>a[i];
			cnt+=(a[i]==i);
		}
		if(n==1||n==2)
		{
			cout<<"Alice"<<endl;
		}
		else if(n>=3)
		{
			cnt=n-cnt;
			if(f=="Alice")
			{
				if(cnt==2)cout<<"Alice"<<endl;
				else cout<<"Bob"<<endl;
			}
			else 
			{
				if(cnt==0||(n==3&&cnt==3))cout<<"Alice"<<endl;
				else cout<<"Bob"<<endl;
			}
		}
	
	}
}

L.Last Chance: Threads of Despair

题面:
亲爱的出题人,我下载了《炉石传说》。为什么我的“绝望之线”是一张三费卡牌呢?

—Pan-fried-chicken

Pan-fried-chicken 是《炉石传说》的忠实玩家。自从游戏在中国大陆恢复运营以来,他就沉迷其中,并在标准模式下达到了2级白银等级。今天,在使用死亡骑士上分时,他遇到了一个强大的对手,Stewed-chicken,并且只剩下\(1\)点生命值。为了生存,Pan-fried-chicken 必须消灭Stewed-chicken 的所有随从。幸运的是,他可以使用法术卡牌和他随从的攻击来实现这个目标。

具体来说,这场游戏涉及两个阵营:Pan-fried-chicken 和 Stewed-chicken。每个阵营都有一些随从。第\(i\)个随从有\(h_i\)点生命值。现在是Pan-fried-chicken 的回合,他的每个随从最多可以攻击对方阵营的任意一个随从一次。当一个随从攻击另一个随从时,两个随从都会失去\(1\)点生命值。如果一个随从的生命值降到\(0\)或更低,它就会死亡,不再能够攻击或被攻击。

为了实现他的目标,Pan-fried-chicken 施放了法术“绝望之线”,导致每个随从死亡时都会爆炸,使所有随从的生命值减少\(1\)点。如果爆炸导致其他随从死亡,其他随从也会立即爆炸。在所有爆炸效果结束后,Pan-fried-chicken 才能让他的随从攻击Stewed-chicken 的随从。他可以选择任意顺序让他的随从攻击。他想知道是否存在一种攻击顺序,能让Pan-fried-chicken 消灭Stewed-chicken 的所有随从。
输入:

每个测试文件包含多个测试用例。第一行包含测试用例的数量\(T\)\(1 \leq T \leq 5 \times 10^5\))。测试用例的描述如下。

每个测试用例的第一行包含两个整数\(n\)\(m\)\(1 \leq n, m \leq 5 \times 10^5\)),表示Fried-chicken的随从数量和Stewed-chicken的随从数量。

第二行包含\(n\)个整数\(h_1, h_2, \dots, h_n\)\(1 \leq h_i \leq 10^9\)),其中\(h_i\)表示Fried-chicken的第\(i\)个随从的生命值。

第三行包含\(m\)个整数\(h'_1, h'_2, \dots, h'_m\)\(1 \leq h'_i \leq 10^9\)),其中\(h'_i\)表示Stewed-chicken的第\(i\)个随从的生命值。

对于每个测试文件,保证所有测试用例中所有\(n\)的总和不超过\(5 \times 10^5\),所有\(m\)的总和不超过\(5 \times 10^5\)
输出:

对于每个测试用例,如果Fried-chicken能够消灭Stewed-chicken的所有随从,则输出"Yes";否则,输出"No"。

你可以以任意大小写输出答案。例如,字符串"yEs"、"yes"、"Yes"和"YES"都将被视为肯定回答。
样例:
3
3 2
1 1 4
2 6
3 2
1 1 4
2 7
2 1
100 100
2
————————
Yes
No
Yes

3
7 1
1 1 1 1 1 1 1
9
5 2
3 4 5 6 7
1 6
5 3
3 4 5 6 7
1 5 7
——————————
No
No
Yes
思路::发现如果维护最大连锁爆炸才是最优的,因为打生命值小的仆人和打大的是一样的,都是生命值减少一。主要是因为爆炸了可以对敌方所有仆从造成伤害,所以维护爆炸优于一直攻击敌方生命最大仆从.当然这题为队友实现的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=700005;
ll a[N];
ll b[N];
void solve(){
	ll n,m;
	scanf("%lld %lld",&n,&m);
	ll att=0;
	ll exp=0;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		a[i]--;
	}
	for(int i=1;i<=m;i++){
		scanf("%lld",&b[i]);
	}
	sort(a+1,a+1+n);
	ll jd=0;
	for(int i=1;i<=n;i++){
		if(a[i]==0){
			jd=1ll;
		}else{	
			att++;//总攻击
		}
	}
	att+=jd;//第一个1造成2伤害
	sort(b+1,b+1+m);
	int l=1;
	while(a[l]==0&&l<=n){
		l++;exp++;
	}
	for(int i=1;i<=m;i++){
		while(a[l]<=exp&&l<=n){
			exp++;l++;//n的自爆
		}
		if(att+exp<b[i]){
			printf("NO");
			return ;
		}else{
			att-=max(0ll,b[i]-exp);//b[i]exp;
			exp++;
		}
	}
	printf("YES");
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
		printf("\n");
	}
	return 0;
}
/*
1
3 2
1 2 4
2 7

1
5 3
3 5 5 6 7
1 5 7
*/

M.Matrix Construction

题面:
构建一个矩阵,样本中包含一个测试用例“2 3”……我们最近是不是见过类似的问题?

—Stewed-chicken

Mary 热爱构建矩阵!

今天,Mary 想要将一个长度为\(n \times m\)的排列\(^{\dagger}\)填充到一个\(n \times m\)的矩阵\(A\)中,使得任意两个相邻元素的和都是唯一的。

换句话说,对于任意\(1 \leq x_1,x_2,x_3,x_4 \leq n, 1 \leq y_1,y_2,y_3,y_4 \leq m\),如果满足以下所有条件:

  • \(x_2 \geq x_1, y_2 \geq y_1, x_4 \geq x_3, y_4 \geq y_3\)
  • \(|x_2-x_1|+|y_2-y_1|=1, |x_4-x_3|+|y_4-y_3|=1\)
  • \((x_1,y_1) \neq (x_3,y_3)\)\((x_2,y_2) \neq (x_4,y_4)\)

那么:

\[A_{x_1,y_1}+A_{x_2,y_2} \neq A_{x_3,y_3}+A_{x_4,y_4} \]

例如,当\(n=2\)\(m=3\)时,矩阵\(B\)是一个有效的解决方案,而矩阵\(C\)则不是有效的,因为\(C_{1,1}+C_{2,1}=C_{1,2}+C_{1,3}\)

\[B = \begin{bmatrix} 1 & 3 & 2 \\ 6 & 5 & 4 \end{bmatrix}, \quad C = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \]

给定\(n\)\(m\),是否可以满足上述所有条件?如果是,请输出一个有效的解决方案。

\(^{\dagger}\) 长度为\(n\)的排列是一个由\(n\)个不同的整数组成的数组,这些整数从1到\(n\),顺序任意。例如,\([2,3,1,5,4]\)是一个排列,但\([1,2,2]\)不是排列(数组中2出现了两次),\([1,3,4]\)也不是排列(\(n=3\)但数组中有一个4)。
输入:
每个测试文件包含多个测试用例。第一行包含测试用例的数量\(T\)\(1 \leq T \leq 10^4\))。测试用例的描述如下。

每个测试用例的第一行包含两个整数\(n,m\)\(1 \leq n,m \leq 1000\))。

对于每个测试文件,保证所有测试用例中\(n \times m\)的总和不超过\(10^6\)
输出:

对于每个测试用例,首先输出一行,表明是否存在有效的解决方案。如果存在有效的解决方案,输出"Yes";否则,输出"No"。你可以以任意大小写输出答案。例如,字符串"yEs"、"yes"、"Yes"和"YES"都将被视为肯定回答。

如果存在有效的解决方案,你还必须输出\(n\)行,每行包含\(m\)个整数。第\(i\)行的第\(j\)个数字表示矩阵中第\(i\)行和第\(j\)列的数字。你必须确保输出的数字构成一个长度为\(n \times m\)的排列。如果有多个解决方案,你可以输出其中的任意一个。
样例:
2
1 1
2 3
————
yEs
1
YES
1 3 2
6 5 4
思路:从左上角进行bfs,然后从1~n逐步分布就好了,因为题目的意思是位置对不一样的相邻两个位置的数字之和的所有可能不能重复,显然小的靠近小的,大的靠近大的就行了

#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<functional>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//#include<bits/stdc++.h>
#include <unordered_map>
#define ll            long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
//using namespace __gnu_pbds;
mt19937 rnd(time(0));
const ll p = 998244353;
const ll mod = 998244353;
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);
}
struct s
{
	ll l, r;
	bool operator<(const s& a)const
	{
		return l < a.l;
	}
};
ll a[3000][3000];
bool vi[2500][2500];
ll d[4]={0,1,0,-1};
ll e[4]={-1,0,1,0};
ll n,m;
void bfs(ll x,ll y)
{
	for(ll i=1;i<=n;i++)
	{
		for(ll j=1;j<=m;j++)
		vi[i][j]=0;
	}
	queue<pair<ll,ll>>q;
	q.push({1,1});
	ll sz=1;
	while(!q.empty())
	{
		ll nx=q.front().first;
		ll ny=q.front().second;
		q.pop();
		if(vi[nx][ny])continue;
		vi[nx][ny]=1;
		a[nx][ny]=sz;
		sz++;
		for(ll i=0;i<=3;i++)
		{
			ll ux=nx+d[i];
			ll uy=ny+e[i];
			if(ux<1||ux>n||uy<1||uy>m||vi[ux][uy])continue;
			q.push({ux,uy});
		}
	}
}
int main()
{
	ll t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		cout<<"YES"<<endl;
		bfs(1,1);
		for(ll i=1;i<=n;i++)
		{
			for(ll j=1;j<=m;j++)
			{
				cout<<a[i][j]<<" ";
			}
			cout<<endl;
		}
	}
}
posted @ 2025-01-13 19:03  长皆  阅读(42)  评论(0编辑  收藏  举报