专栏文章

非常规题做题记录

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mindhi2k
此快照首次捕获于
2025/12/02 00:37
3 个月前
此快照最后确认于
2025/12/02 00:37
3 个月前
查看原文

A.Ancestor Relation

拿到题目想到第一件事一定是先判无解。
容易发现,合法的 ai,j=1a_{i,j}=1 的意思是 i,ji,j 之间有祖先关系。换种方式说,当且仅当 i,ji,j 在不同子树中才满足 ai,j=0a_{i,j}=0
那么无解的第一个条件就很明显,11 是树的根所以 11 和所有点都有关系,因此 a1,i=0a_{1,i}=0 就是无解。
假设 u,vu,v 两点,uuvv 父亲,那么 uu 的祖先一定全是 vv 的祖先,但是 vv 的祖先不一定是 uu 的祖先。换成本题的 aa 数组就是 auav=ava_u|a_v=a_v 那么 uu 就是 vv 的祖先,即 au,v=1a_{u,v}=1 (auav=aua_u|a_v=a_u同理)
因此我们便找到第二个判无解条件,满足上面两条件但 au,v=0a_{u,v}=0 就是一个无解。反过来如果两个条件都不满足但是 au,v=1a_{u,v}=1 也是无解。
接下来考虑计算答案,但是两个不怎么相同的 aia_i aja_j 似乎很难直接计算贡献,那么直接考虑特殊情况。
ai=aja_i=a_j 时,根据上面再稍微思考一下可以想到 i,ji,j 一定是在一条链上的,链中点的顺序是无所谓的所以每找到一条链上的点他们的贡献是点个数的阶乘。
剩下的因为没有在链上的性质无法交换位置,因此位置被固定无法贡献答案。
可以用bitset优化到 O(n3w)O(\frac{n^3}{w}) 但我没用。
code:
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=405;
const int mod=998244353;
int n,t;
int a[N][N];
int tag[N],lc[N];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>t;
	lc[0]=1;
	for(int i=1;i<=400;i++) lc[i]=lc[i-1]*i,lc[i]%=mod;
	while(t--){
		memset(tag,0,sizeof(tag));
		int ans=1;
		cin>>n;
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
		bool flag=0;
		for(int i=1;i<=n;i++) if(!a[1][i]){
			cout<<0<<"\n";
			flag=1;
			break;
		}
		if(flag) continue;
		for(int i=1;i<=n;i++){
			for(int j=i+1;j<=n;j++){
				bool f1=1,f2=1,f3=1;
				for(int w=1;w<=n;w++){
					if(a[i][w]!=a[j][w]) f3=0;
					if(a[i][w]&&!a[j][w]) f1=0;
					if(!a[i][w]&&a[j][w]) f2=0;
				}
				if(f3) continue;
				if((f1&&!f2)||(!f1&&f2)){if(!a[i][j]) flag=1;}
				if((f1&&f2)||(!f1&&!f2)){if(a[i][j]) flag=1;}
				if(flag==1) break;
			}
			if(flag==1) break;
		}
		if(flag){
			cout<<0<<"\n";
			continue;
		}
		for(int i=1;i<=n;i++){
			if(tag[i]) continue;
			int p=0;
			if(i>1) p++;
			for(int j=i+1;j<=n;j++){
				bool f=1;
				for(int k=1;k<=n;k++) if(a[i][k]!=a[j][k]) f=0;
				if(f) tag[j]=1,p++;
			}
			if(p) ans*=lc[p],ans%=mod;
		}
		cout<<ans<<"\n";
	}
	return 0;
}

B.Tree Restoring

容易联想到直径。直径两端的点相隔的距离一定是最远的,并且存在的点一定是两个及以上,因此想到第一种判无解。
根据树的性质及观察样例可知,最远距离在树上一定是连续的,不可能出现父亲最远距离是 dd 儿子是 d+2d+2 ,因此得到第二种判无解。
  1. 如果最远距离是偶数,那么直径所在链形成的数一定是: a,a1,a2   ...   ak   ...   a1,aa,a-1,a-2~~~...~~~a-k~~~...~~~a-1,a 根据直径性质可得且 aka-k 只有一个
  2. 如果最远距离是奇数,则是: a,a1,a2   ...   ak,ak   ...   a1,aa,a-1,a-2~~~...~~~a-k,a-k~~~...~~~a-1,a 同理,且 aka-k 有且仅有两个
剩余的点我们可以挂在直径上,它的最远距离就是它挂着点的最远距离加1,这也是为什么奇数时 aka-k 有且仅有 22
用桶判个数即可,这就是第三种判无解(其实可以涵盖第二种)

C.Vasya And The Matrix

一种很巧妙的做法。
无解很简单,整个矩形异或两遍一定是 00 ,不为 00 无解。
构造题就要构造的越简单越好,最好是每行只有一个数。假设我们把所有的数全部填在同一列就很好满足行的异或和,满足列的异或和就是放在同一行。
那么我们不妨让它们都放在最后一行和最后一列(其它也可以,只需保证行列互不干涉)。最后一个位置暂时不填,它需要满足两个约束,设答案矩形为cc
cn,1c_{n,1} ^ cn,2c_{n,2} ^ ...... ^ cn,m=anc_{n,m}=a_n
c1,mc_{1,m} ^ c2,mc_{2,m} ^ ...... ^ cn,m=bmc_{n,m}=b_m
因为一个合法矩形异或两遍一定是 00 所以
a1a_1 ^ a2a_2 ^ ...... ^ ana_n^b1b_1 ^ b2b_2 ^ ...... ^ bm=0b_m=0
根据我们的填法
cn,1=b1 ... cn,m1=bm1c_{n,1}=b_1~...~c_{n,m-1}=b_{m-1} c1,m=a1 ... cn1,m=an1c_{1,m}=a_1~...~c_{n-1,m}=a_{n-1}
代回移项,观察两式
b1b_1 ^ b2b_2 ^ ...... ^ an=cn,ma_n=c_{n,m}
a1a_1 ^ a2a_2 ^ ...... ^ bm=cn,mb_m=c_{n,m}
左式相异或值为 00 因此 cn,mc_{n,m} 值是唯一的

评论

0 条评论,欢迎与作者交流。

正在加载评论...