306 words
2 分钟minutes
Cards (ABC 247 F)

AtCoder - abc247_f

Problem Summary#

You have NN cards. Each card has two sides — the front shows a number PiP_i and the back shows QiQ_i. Both sequences PP and QQ are permutations of (1,2,,N)(1, 2, \dots, N). Count the number of subsets of cards such that every number from 11 to NN appears on at least one chosen card. Output the answer modulo 998244353998244353. (1N2×105)(1 \le N \le 2 \times 10^5)

Approach#

Build a graph by connecting the two numbers on each card. Since PP and QQ are permutations, every value appears exactly twice, so every vertex has degree 22 and the resulting graph is a disjoint union of cycles.

Consider a simpler sub-problem first: on a chain of mm numbers 1,2,,m1, 2, \dots, m, count the ways to pick a subset such that for every pair of adjacent numbers at least one is chosen. Splitting by whether mm is picked, let f(m)f(m) denote the answer. We have f(1)=2f(1) = 2, f(2)=3f(2) = 3, and f(m)=f(m1)+f(m2)f(m) = f(m-1) + f(m-2) — Fibonacci-like.

Now the real sub-problem: on a cycle of mm numbers, count the subsets where for every vertex at least one of its two incident edges is chosen. Let g(m)g(m) denote the answer. Casework on whether the edge (1,m)(1, m) is picked gives g(1)=1g(1) = 1, g(2)=3g(2) = 3, and g(m)=f(m1)+f(m3)g(m) = f(m-1) + f(m-3). A quick check reveals g(m)=Lmg(m) = L_m, the mm-th Lucas number.

Multiply g(cycle length)g(\text{cycle length}) across every cycle in the graph to get the final answer.

Code#

#include<bits/stdc++.h>
using namespace std;
long long a[200005];
long long mod=998244353;
int p[200005];
int q[200005];
int fa[200005];
int siz[200005];
int vis[200005];
int findd(int x)
{
return fa[x]==x?x:(fa[x]=findd(fa[x]));
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
for(int i=1;i<=n;i++)scanf("%d",&q[i]);
for(int i=1;i<=n;i++){fa[i]=i;siz[i]=1;}
for(int i=1;i<=n;i++)if(findd(p[i])!=findd(q[i]))
{
siz[findd(q[i])]+=siz[findd(p[i])];
fa[findd(p[i])]=findd(q[i]);
}
a[0]=2;
a[1]=1;
for(int i=2;i<=n;i++)a[i]=(a[i-1]+a[i-2])%mod;
long long ans=1;
for(int i=1;i<=n;i++)if(!vis[findd(i)])
{
ans=ans*a[siz[findd(i)]]%mod;
vis[findd(i)]=1;
}
printf("%lld\n",ans);
return 0;
}
Cards (ABC 247 F)
https://jerryblack.vercel.app/posts/cards-abc247f-en/
作者Author
逸少( ̄^ ̄)ゞJerry Black
发布于Published at
2022-04-29
许可协议License
CC BY-NC-SA 4.0