ABC470F并查集+组合数学
写题解背景请看这篇。
我恨 C 题!
传送门
洛谷,AtCoder。
正文
::::info[分析] 题目无非就是给你一堆位置,你可以去交换这些位置上的字符。
我们可以把每个可能的交换想成一条无向边,建图,很容易发现,如果两个点不在一个联通块内,它们毫无关系,完全不会影响。
所以,我们只要统计各个联通块中的排列数,最后乘法原理就可以了。
::::
::::info[计算]
假设没有
假设这个连通块有 a 的个数为 b 的个数为 z 的个数为
现将所有字符全排列,但因为相同字符可以互换位置,所以还要除以每个相同字符的全排列。
单个连通块内可组成
那要求偶数次怎么处理呢?
现在假设原来的排列是
从
分两种情况讨论。
::::
::::info[某个连通块内有相同字符]
假设连通块内,点
- 将
p 点字符移动到x ,因为是连通块,所以必有一条路径,花费步数t1 。 - 将
q 点字符移动到y ,因为是连通块,所以必有一条路径,花费步数t2 。 - 交换两个字符,花费步数
1 。 - 然后原路返回,花费步数
t1+t2 。
最终虽然原排列点
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
#define LL long long
#define F(i,k,n) for(int i=(k);i<=(n);++i)
#define RF(i,k,n) for(int i=(k);i>=(n);--i)
using namespace std;
const int MOD=998244353;
int fa[200005];
int ch[26];
int find(int x){
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
void join(int x,int y){
int xx=find(x);
int yy=find(y);
if(xx==yy)
return;
fa[xx]=yy;
return;
}
struct node{
int x;
int anc;
}sct[200005];
LL fac[200005];
LL inv[200005];
int fpow(LL x,int k){
LL ans=1;
while(k>0){
if(k&1){
(ans*=x)%=MOD;
}
k>>=1;
(x*=x)%=MOD;
}
return ans;
}
void init(int n){
fac[0]=1;
F(i,1,n){
fac[i]=fac[i-1]*i%MOD;
}
inv[n]=fpow(fac[n],MOD-2);
RF(i,n-1,0){
inv[i]=inv[i+1]*(i+1)%MOD;
}
return;
}
/*int c(int x,int y){
return fac[x]*inv[x-y]%MOD;
}*/
bool cmp(node x,node y){
return x.anc<y.anc;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,k;
cin>>n>>k;
init(n);
string s;
cin>>s;
s=' '+s;
F(i,1,n){
fa[i]=i;
}
F(i,1,k){
int u,v;
cin>>u>>v;
join(u,v);
}
F(i,1,n){
sct[i].anc=find(i);
sct[i].x=i;
}
sort(sct+1,sct+n+1,cmp);
LL ans=1;
vector<int>v;
bool bl=0;
F(i,1,n){
if(i!=1&&sct[i].anc!=sct[i-1].anc){
memset(ch,0,sizeof(ch));
for(int it:v){
++ch[s[it]-'a'];
}
LL sum=fac[v.size()];
F(j,0,25){
if(ch[j]>1){
bl=1;
}
(sum*=inv[ch[j]])%=MOD;
}
(ans*=sum)%=MOD;
v.clear();
}
v.push_back(sct[i].x);
}
memset(ch,0,sizeof(ch));
for(int it:v){
++ch[s[it]-'a'];
}
LL sum=fac[v.size()];
F(i,0,25){
if(ch[i]>1){
bl=1;
}
(sum*=inv[ch[i]])%=MOD;
}
(ans*=sum)%=MOD;
if(bl)
cout<<ans;
else
cout<<ans*inv[2]%MOD;
return 0;
}
提交记录。 ::::