Topcoder SRM592-Div1-Lv2 LittleElephantAndPermutationDiv1

题意

\(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;
}
posted @ 2024-06-02 21:48  MessageBoxA  阅读(32)  评论(0)    收藏  举报