Practice on Codeforces and Atcoder in April

1811D

性质:

F02+F12+F22++Fn2=Fn·Fn+1

证明:数学归纳法:Fn·Fn+1=Fn(Fn+Fn1)=Fn2+FnFn1

题目等价于是确定了 F0 的位置,是否可以分割出其他。

考虑类似螺旋的分割方式,从大到小分割(Fn=Fn1+Fn2),每一次贪心地放最大的正方形,以达到缩小问题规模即可。

当然这里利用了对称性,直接迭代实现。

#define int long long
int n,a,b,f[55];
signed main(){
	f[0]=f[1]=1;
	for(int i=2;i<=45;i++)f[i]=f[i-1]+f[i-2];
	int t;cin>>t;
	while(t--){
		cin>>n>>a>>b;int tag=0;swap(a,b);
		for(int i=n;i;--i){
			if(a>f[i])a-=f[i];
			else if(a>f[i-1])tag=1;
			swap(a,b);
		}
		if(tag)cout<<"No\n";
		else cout<<"Yes\n";
	}
} 

1819B

考的时候想歪了。

题目意思即为给定一些小矩形,这些小矩形是由大矩形每一次进行横切/纵切得到(切为两部分后其中一部分就不动了,矩形不可旋转翻转)

引理1:解的个数最多只有二

证明:小矩形中长和宽的最大值分别对应答案矩形的长宽,且面积一定

这是一个重要的性质,问题化为判定答案的合法性

考虑模拟这个过程,显然不会超时

使用队列进行优化。

设答案矩阵长宽为 (h,w),每一个矩阵的长宽为 (hi,wi)

我们现在讨论 \existi[1,n],hi=h 的情况

x=i=1n[hi=h]wi,则表示这些矩阵都是一次性砍掉的

那么问题就化为判断 (h,wx) 的合法性,设 w=wx

再设 x=i=1n[wi=w]hi,则问题化为判断 (hx,w) 的合法性

容易发现这是一个递归的过程,有解的充要条件是最后某维度化为0,且过程中 x>0

从这里可以看出:核心在于将求解答案化为判定答案,再以题目所给方式倒推证明

1821D

1770D

题意:

Koxia 和 Mahiru 正在玩一个游戏。游戏使用 a,b,c 三个长度为 n 的数组,共进行 n 轮。

每一轮中,Koxia 先在 ai,bi,ci 中选择一个数字,Mahiru 再从未选择的两个数字中选择一个。

如果 n 轮后 Mahiru 选择的数字刚好包含 1n 中每个数字各一个(即为 1n 的一个排列),则 Koxia 获胜。否则,Mahiru 获胜。

假设双方都采取最优策略,给定 a,b 数组,求使得 Koxia 必胜的 c 数组的个数。

题解:

因为两人都足够聪明,所以想赢就只有一种可能——先手可以限制后手怎么走

回到这个问题,如果后手方案确定,当且仅当剩下两个数是一样的,这样后手就会被先手牵着鼻子走

那么进行分类讨论可以确定必要条件:

  1. ai=bi 此时 cin 种取法
  2. aibi 此时 ci 有两种取法,分别对应 ai,bi

但这个条件不够充分。

对于这类或关系的处理,图论建模是一个很好的方法。

我们将一对ai,bi进行连边,问题化为每条边都必须指定端点的其中之一,不重不漏。考虑什么条件下是合法的。

下面我们证明有且仅有环是合法的,我们分连通块来讨论这个问题,显然不同连通块是 不会互相影响的。

先证充分性:按着环跑一圈一定是合法的

再证必要性:

  1. 假设它是一棵树,则 |E|<|V|,必定存在点连不到(树根),答案变0
  2. 假设它连通,但 |E|>|V|,则必然会取到重复的,答案直接变0

统计|V|>1环的个数(并查集即可),记为 c|V|=1 环的个数记为s

ans=2cns

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 205050
int f[N],num,a[N],b[N],n,m,ans=1,dfn[N],low[N],dcc,cnt[N],scc[N],tot=1,vis[N],siz[N],V[N];
int get(int x){
	return x==f[x]?x:f[x]=get(f[x]);
}
void solve(){
	for(int i=1;i<=n;i++){
		if(i!=f[i]||V[i])continue;
		if(siz[i]==cnt[i]&&vis[i]){
			ans=1ll*ans*n%998244353;continue;
		}
		ans=1ll*ans*(siz[i]==cnt[i])*2%998244353;
	}
}
void clear(){
	for(int i=1;i<=n;i++)siz[i]=cnt[i]=V[i]=vis[i]=0;
	dcc=num=0,tot=ans=1;
}
int main(){
	int t;cin>>t;
	while(t--){
		clear();
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];f[i]=i;siz[i]=1;
		}
		for(int i=1;i<=n;i++)cin>>b[i];
		for(int i=1;i<=n;i++){
				int u=get(a[i]),v=get(b[i]);
				if(u==v){
					if(a[i]==b[i])vis[u]=1;
					cnt[v]++;continue;
				}
				f[u]=v,cnt[v]+=cnt[u]+1,siz[v]+=siz[u],vis[v]|=vis[u];
		}
		solve();
		cout<<ans<<"\n";	
	}
}
posted @   spdarkle  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示