[ABC247F] Cards
前言
某同学在补题开始后竟用 \(0\) 罚时过前三道题,而考试时却一道题也切不出来,可还是吊打我。
思路
我们可以发现,在正面包含 \(i\) 和反面包含 \(i\) 的两张卡片中必须选一张,那么我们就可以对于包含 \(i\) 的两张卡片连边,然后我们就能得到一些环,因为对于每一张卡片的出度都为 \(2\) 然后我们就可以用一个排列组合来计算方案数。我们先来举个例子,当环内大下为 \(1\) 时共 \(1\) 中取法,当大下为 \(2\) 时共 \(3\) 种取法,当大小为 \(3\) 时共 \(4\) 种取法,当大小为 \(4\) 时共 \(7\) 种取法。乍一看没什么规律,再仔细一看,这不就是一个变种的斐波那契数列吗?然后,我们就可以先预处理出来即可,这里统计环的大下可以用并查集完成。
代码
#include <bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(fasle);cin.tie(NULL);cout.tie(NULL)
#define int long long
#define ri register int
#define rep(i,x,y) for(ri i=x;i<=y;i++)
#define rep1(i,x,y) for(ri i=x;i>=y;i--)
#define il inline
#define fire signed
#define pai(a,x,y) sort(a+x,a+y+1)
using namespace std ;
il int qmi(int a,int b) {
int res=1;
while(b) {
if(b&1) res=(res*a);
a=a*a;
b>>=1;
}
return res;
}
void read(int &x) {
x=false;
ri f=1;
char c=getchar();
while(c>'9'||c<'0') {
if(c=='-') f=-1;
c=getchar();
}
while(c-'0'<=9&&c>='0') {
x=x*10+c-'0';
c=getchar();
}
x*=f;
}
void print(int x) {
if(x>=10) print(x/10);
putchar(x%10+'0');
}
#define gcd(x,y) __gcd(x,y)
#define lcm(x,y) x*y/gcd(x,y)
int n;
pair<int,int>a[200100];
const int mod=998244353;
int f[200100];
int fa[200100],siz[200100];
int find(int x) {
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
fire main() {
f[1]=1;
f[2]=3;
rep(i,3,200000) f[i]=(f[i-1]+f[i-2])%mod; //预处理
cin>>n;
rep(i,1,n) {
int x;
cin>>x;
a[x].first=i;
}
rep(i,1,n) {
int b;
cin>>b;
a[b].second=i;
}
rep(i,1,n) {
fa[i]=i;//初始化
siz[i]=1;
}
rep(i,1,n) {
int tx=find(a[i].first),ty=find(a[i].second); //合并
if(tx==ty) continue;
siz[tx]+=siz[ty];
siz[ty]=0;
fa[ty]=tx;
}
int res=1;
rep(i,1,n) {
if(fa[i]==i) {
res=(res*f[siz[find(i)]])%mod; //排列组合
// cout<<i<<endl;
}
}
print(res);
return false;
}

浙公网安备 33010602011771号