Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)

题目

给定一个长度为n(n<=1e6)的序列,第i个数ai(1<=ai<=n),

操作:你可以将当前i位置的数和a[i]位置的数交换

交换可以操作任意次,求所有本质不同的数组的数量,答案对1e9+7取模

思路来源

力扣群 潼神

Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)_第1张图片

心得

感觉已经说的很详尽了,甚至没什么需要补充的地方...

不难发现,自环的情况和>=2的环的情况是统一的,所以dfs找环即可

 

组合题更多的是一种无从下手的感觉,需要多培养手玩性质的能力

比如,发现a->b->c到a->c,b->b这个性质,然后再着手计数

代码

#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<e[N];
int stk[N],c,ans=1;
bool vis[N],in[N];
void dfs(int u){
	if(!u)return;
	stk[++c]=u;
	in[u]=1;
	vis[u]=1;
	int v=to[u];
	if(in[v]){//环的情况 统一了自环的情况
		int res=1,sub=0;
		while(c){
			int w=stk[c--];in[w]=0;
			res=1ll*res*(deg[w]+1)%mod;
			sub=(sub+deg[w])%mod;
			if(w==v)break;
		}
		res=(res+mod-sub)%mod;
		ans=1ll*ans*res%mod;
	}
	if(!vis[v])dfs(v);
}
int main(){
	sci(n);
	rep(i,1,n){
		sci(v);
		to[i]=v;
		deg[v]++;
	}
	rep(i,1,n){
		if(!vis[i]){
			dfs(i);
		}
		while(c){
			int w=stk[c--];in[w]=0;
			ans=1ll*ans*(deg[w]+1)%mod;
		}
	}
	printf("%d\n",ans);
	return 0;
}

 

 

你可能感兴趣的:(组合数学(容斥原理),组合数学,计数)