错位排序

对于没有限制的纯错位排序

\(dp[i]=(i-1)*(dp[i-1]+dp[i-2]),dp[0]=1,dp[1]=0\)

理解方式:考虑已经找完前i-1个数,第i个数,如果把i放进pos的位置,如果pos放进i位置,那么剩下i-2个数还是错排\(dp[i-2]\);如果不把i放进pos位置,相当于剩下i-2个数每个数有1个位置不能放,pos不能放i位置,满足错排的本质要求所以是\(dp[i-1]\).

对于有限制的错排:\(dp[i][j]表示i个数有j个没有限制(放哪都行),剩下的有1个互不重复位置不能放\)

\(dp[i][j]=dp[i-1][j-1]+dp[i][j-1]\),还不知道怎么理解

应用:beautiful

image

点击查看代码






#include<bits/stdc++.h>
using namespace std;
#define rint register int
#define _f(i,a,b) for(rint i=a;i<=b;++i)
#define f_(i,a,b) for(rint i=a;i>=b;--i)
#define chu printf
#define ll long long
inline ll re()
{
	ll h=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*h;
}
const int N=2010;
const ll mod=19990921;
int t1[N],vis[N],t2[N],zh[N][N];
int n;
ll tot,jc[N],cp[N][N];
#define lowbit(x)  (x&(-x))
inline ll qpow(ll a,ll b)
{
	ll nsa=1;

	//chu("a:%d b:%d\n",a,b);
	while(b)
	{
		if(b&1)
		{
			nsa=nsa*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	//chu("nsa:%lld\n",nsa);
	return nsa;
}
inline void add(int *s ,int x,int v)
{
	while(x<=n)
	{
		s[x]+=v;
		x+=lowbit(x);
	}
}
inline int query(int *s,int x)
{
	int ans=0;
	while(x)
	{
		ans+=s[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	//freopen("asn.txt","r",stdin);
	n=re();
	_f(i,1,n)
	_f(j,1,n)zh[i][j]=re();
	jc[0]=jc[1]=1;
	_f(i,2,n)jc[i]=jc[i-1]*i%mod;
	_f(i,1,n)add(t1,i,1);
	_f(i,1,n)
	{
		tot=(tot+query(t1,zh[1][i]-1)*jc[n-i]%mod)%mod;
		add(t1,zh[1][i],-1);
	}
	cp[0][0]=1;
	_f(i,2,n)
	cp[i][0]=(ll)(i-1)*(cp[i-1][0]+cp[i-2][0])%mod;
	_f(i,1,n)
	{
		_f(j,1,n)
		cp[i][j]=(cp[i-1][j-1]+cp[i][j-1])%mod;
	}
	//chu("nowtot:%d\n",tot);
	tot=tot*qpow(cp[n][0],n-1)%mod;


	_f(i,2,n)
	{
		_f(j,0,n)vis[j]=t1[j]=t2[j]=0;
		ll sum=0;
		_f(j,1,n)
		{
			if(!vis[zh[i-1][j]])
			{
				vis[zh[i-1][j]]=1;
				add(t2,zh[i-1][j],1);
			}
			ll tmp=zh[i][j]-query(t2,zh[i][j]-1);
			//printf("tmp:%lld\n",tmp);
			//zh[i][j]在zh[i-1][j]出现也可以填在tmp里
			//zh[i-1][j]>=zh[i][j]都是不用删除的
			//tmp计算的可以填在zh[i][j]位置的,在前面所有i-1和i都没出现过
			//所以一定同时在i-1和i的后j+1~n位置出现,符合错排
			sum=(sum+(tmp-1)*cp[n-j][query(t2,n)-(j-1)]%mod)%mod;
			tmp=query(t2,zh[i][j]-1)-query(t1,zh[i][j]-1);
			
			if(zh[i-1][j]<zh[i][j]&&query(t1,zh[i-1][j])-query(t1,zh[i-1][j]-1)!=1)
			tmp--;
			sum=(sum+tmp*cp[n-j][query(t2,n)-j]%mod)%mod;
			add(t1,zh[i][j],1);
			if(!vis[zh[i][j]])
			{
				vis[zh[i][j]]=1;
				add(t2,zh[i][j],1);
			}
		}
		tot=(tot+sum*qpow(cp[n][0],n-i)%mod)%mod;
		//printf("add:%lld\n",sum);
	}
	chu("%lld",(tot+1)%mod);
	return 0;
}
/*
L.(opt,pos,val)
R.(opt,pos,val)

5 4
1
5
3
4
2
5
1
4
2
*/
posted on 2022-09-08 19:21  HZOI-曹蓉  阅读(161)  评论(0编辑  收藏  举报