首页 > 技术文章 > Codeforces Round #777 (Div. 2)

ZCETHAN 2022-03-12 08:30 原文

先吐槽一句,怎么会有人出阅读理解+分类讨论题啊。。。

A

给出一个数 \(n\),让你构造一个最大的数,使得这个数各位数字之和为 \(n\) 且不含 \(0\) 也没有两个相同的数相邻。那直接构造 \(12\) 交替就行了,分类一下模 \(3\) 的余数然后直接输出就行啦。

My Code
using namespace std;
void solve(){
	int n;cin>>n;
	if(n%3==0){
		rep(i,1,n/3) cout<<"21";
		cout<<'\n';
	}else if(n%3==1){
		cout<<"1";
		rep(i,1,n/3) cout<<"21";
		cout<<'\n';
	}else{
		cout<<"2";
		rep(i,1,n/3) cout<<"12";
		cout<<'\n';
	}
}
int main()
{
	ios::sync_with_stdio(0);
	int T;
	for(cin>>T;T--;)
		solve();
	return 0;
}

B

定义一个子矩阵是好的,当且仅当这个子矩阵内全是 \(1\) 并且不被其它任意一个全是 \(1\) 的矩阵包含。

定义一个矩阵是优雅的,当且仅当没有两个好的矩阵相交。

判断矩阵是不是好的。

考虑一个 \(2\times 2\) 的子矩阵内,如果 \(1\) 的个数是 \(4\) 的(也就是满的),那这一定只被一个好的矩阵包含。同样的只有 \(2\) 及以下个点也只能被一个好的矩阵包含(要不然就被最大的好的矩阵包含它就不好了)。但是如果是 \(3\) 的话,那在拐弯的地方那个格子会被包含 \(2\) 次。

所以扫一遍有没有 \(2\times 2\) 的矩阵内有 \(3\)\(1\) 的。

My Code
using namespace std;
const int MAXN=110;
char mp[MAXN][MAXN];
void solve(){
	int n,m;cin>>n>>m;
	rep(i,1,n) rep(j,1,m) cin>>mp[i][j];
	rep(i,1,n-1) rep(j,1,m-1){
		int cnt=mp[i][j]-'0'+mp[i+1][j]-'0'+mp[i][j+1]-'0'+mp[i+1][j+1]-'0';
		if(cnt==3){
			cout<<"NO\n";
			return;
		}
	}cout<<"YES\n";
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;for(cin>>T;T--;)
		solve();
	return 0;
}

C

每次可以选中一个子矩阵,并将其黑白染色(左上是白)。最初是空白的矩阵,求构造方案使得达到最终状态。

构造,我们能让任意的 \((x,y+1)\) 或者 \((x+1,y)\) 变成黑色并且不对别的产生影响,那只要判断一下 \((1,1)\) 是否是黑的,然后倒着填,每次填一个黑色格子就行了。

My Code
using namespace std;
const int MAXN=110;
struct opt{
	int lx,ly,rx,ry;
};
int a[MAXN][MAXN],cur[MAXN][MAXN];
void solve(){
	int n,m;cin>>n>>m;char c;
	rep(i,1,n) rep(j,1,m) cin>>c,a[i][j]=c-'0',cur[i][j]=0;
	if(a[1][1]){cout<<-1<<'\n';return;}
	vector<opt> ans;
	per(i,n,1) per(j,m,1){
		if(cur[i][j]==a[i][j]) continue;
		if(!a[i][j])
			cur[i][j]=0,ans.pb((opt){i,j,i,j});
		else{
			if(j>1) cur[i][j]=1,cur[i][j-1]=0,ans.pb((opt){i,j-1,i,j});
			else cur[i-1][j]=0,cur[i][j]=1,ans.pb((opt){i-1,j,i,j});
		}
	}cout<<(int)ans.size()<<'\n';
	for(auto s:ans) cout<<s.lx<<' '<<s.ly<<' '<<s.rx<<' '<<s.ry<<'\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;for(cin>>T;T--;)
		solve();
	return 0;
}

D

定义一个数是好数,当且仅当 \(d|a\)\(d^2\nmid a\)。定义一个数是牛逼的当且仅当这个数有至少两种分解因数的方式,使得分解出来的都是好数。

求给出 \(x,d\)\(x\) 是不是牛逼的。

\(x=kd^n\)\(n\) 取最大。然后开始分讨。(下面每个如果都在上面的如果不成立的前提下)

如果 \(n\le1\),那么显然不行。
如果 \(k\) 是合数,那么显然可以。
如果 \(d\) 是质数,那么显然不行。
如果 \(n<3\),那么显然不行。
如果 \(n>3\),那么显然可以。(就你随便拆一个 \(d\) 就行了)
如果 \(n=3\),那么把最后一个 \(d\) 拆开,枚举所有拆法,然后直接判断就行了。

My Code
#define int long long
using namespace std;
bool isp(int x){
	if(x==1) return 1;
	for(int i=2;i*i<=x;i++)
		if(x%i==0) return 0;
	return 1;
}
void solve(){
	int x,d;cin>>x>>d;
	int n=0;while(x%d==0) x/=d,n++;
	if(n<2){cout<<"NO\n";return;}
	if(!isp(x)){cout<<"YES\n";return;}
	if(isp(d)){cout<<"NO\n";return;}
	if(n>3){cout<<"YES\n";return;}
	if(n<=2){cout<<"NO\n";return;}
	for(int i=2;i*i<=d;i++){
		if(d%i) continue;
		int a=i,b=d/i;
		if(x*a%d){
			cout<<"YES\n";
			return;
		}
		if(x*b%d){
			cout<<"YES\n";
			return;
		}
	}cout<<"NO\n";
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;for(cin>>T;T--;)
		solve();
	return 0;
}

E

F

推荐阅读