打辅助.jpg
抢人头.jpg
抢不到我 当 场 把 键 盘 吃 掉 !
每轮同时填格子和数,然后去绝对值。
$f[i][j][k]$ 表示填了前 $i$ 个数和前 $i$ 个位置,空了 $j$ 个位置同时留了 $j$ 个数(我一开始还打算分两个状态来着),已填的部分产生的权为 $k$ 的方案数。
每次转移:
1.第 $i$ 个数填第 $i$ 个位置:空了 $j$ 个位置同时留了 $j$ 个数,产生权 $0$ ,方案数为 $1$;
2.第 $i$ 个数填前面空的格子,以前留的数填第 $i$ 个位置:空了 $j-1$ 个位置同时留了 $j-1$ 个数,产生权 $i+i$ ,方案数 $j^2$ ;
3.第 $i$ 个数填前面空的格子,第 $i$ 个位置留空:空了 $j$ 个位置同时留了 $j$ 个数,产生权 $i-i$ ,方案数为 $j$ ;
4.遗留第 $i$ 个数,以前留的数填第 $i$ 个位置:空了 $j$ 个位置同时留了 $j$ 个数,产生权 $-i+i$ ,方案数为 $j$ ;
5.遗留第 $i$ 个数,第 $i$ 个位置留空:空了 $j+1$ 个位置同时留了 $j+1$ 个数,产生权 $-i-i$ ,方案数 $1$ 。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<bits/stdc++.h>
using namespace std;
const int N=51;
const int Dl=2501;
const int P=1e9+7;
int f[N][N][2*N*N];
int main()
{
int n,m,i,j,k;
scanf("%d%d",&n,&m);
f[0][0][Dl]=1;
for(i=1;i<=n;i++)
for(j=0;j<i;j++)
for(k=-n*n;k<=n*n;k++){
if(j&&k+2*i<=n*n)(f[i][j-1][k+2*i+Dl]+=1ll*f[i-1][j][k+Dl]*j*j%P)%=P;
(f[i][j][k+Dl]+=1ll*f[i-1][j][k+Dl]*(2*j+1)%P)%=P;
if(k-2*i>=-n*n)(f[i][j+1][k-2*i+Dl]+=f[i-1][j][k+Dl])%=P;
}
printf("%d",f[n][0][m+Dl]);
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4370811/blog/4511092