对于没有限制的纯错位排序
\(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
点击查看代码
#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
*/