题意
设 \(A,B\) 为两个长为 \(n\ (\leq50)\) 的排列,定义操作 \(F(A,B)=\sum\limits_{i=1}^{n}\max(A_i,B_i)\),给定 \(n,k\),求有多少种有序对 \((A,B)\) 满足 \(F(A,B)\geq k\),答案模 \(10^9+7\)。
思路
首先还是用经典的思路将无序转为无序,我们假定 \(A\) 是有序的即 \(A={1,2,3,\dots,n}\),然后计数,最后答案在乘回去一个 \(n!\) 即可。
记 \(f[i][j][k]\) 为填了 \(1\sim i\) 位,有 \(j\) 个小于等于 \(i\) 的数填在 \(i\) 后面了,并且所有小于等于 \(i\) 的 \(\max(A_p,B_p)\) 加起来为 \(k\)。
考虑从第 \(i\) 位转移到第 \(i+1\) 位:
情况 | \(j\) 的变化 | \(k\) 的变化 | \(B[1,i]\) 的情况数 |
---|---|---|---|
\(i+1\) 就填在第 \(i+1\) 位 | 不变 | \(+(i+1)\) | \(f[i][j][k]\) |
\(i+1\) 填在小于 \(i+1\) 位,\(i+1\) 位填小于 \(i+1\) 的数 | \(-1\) | \(+2\times(i+1)\) | \(f[i][j][k]\times j^2\) |
\(i+1\) 填在小于 \(i+1\) 位,\(i+1\) 位填大于 \(i+1\) 的数 | 不变 | \(+(i+1)\) | \(f[i][j][k]\times j\) |
\(i+1\) 填在大于 \(i+1\) 位,\(i+1\) 位填小于 \(i+1\) 的数 | \(+1-1\) 不变 | \(+(i+1)\) | \(f[i][j][k]\times j\) |
\(i+1\) 填在大于 \(i+1\) 位,\(i+1\) 位填大于 \(i+1\) 的数 | \(+1\) | 不变 | \(f[i][j][k]\) |
代码
#include<bits/stdc++.h>
#define add(x,y) x=((x)+(y))%P
using namespace std;
typedef long long LL;
const LL P=1e9+7;
const int MAXN=55,MAXM=2505;
int n,m;
LL f[MAXN][MAXN][MAXN*MAXN],ans,fact=1;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
fact=fact*(LL)i%P;
}
f[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=n*n;k++){
if(!f[i][j][k]) continue;
add(f[i+1][j][k+(i+1)],f[i][j][k]*(1+j+j)%P);
add(f[i+1][j+1][k],f[i][j][k]);
if(j>=1) add(f[i+1][j-1][k+2*(i+1)],f[i][j][k]*j*j);
}
}
}
for(int i=m;i<=n*n;i++){
add(ans,f[n][0][i]);
}
cout<<ans*fact%P<<endl;
return 0;
}
标签:LittleElephantAndPermutationDiv1,小于,int,SRM592,位填,times,MAXN,Topcoder,LL
From: https://www.cnblogs.com/SkyNet-PKN/p/18227687