#189 stat(动态规划)
Posted gloid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#189 stat(动态规划)相关的知识,希望对你有一定的参考价值。
容易想到固定第一个排列为1~n,算出答案后乘上n!即可,但这样就离正解走远了。
考虑排列dp的一般套路,将数从大到小加入排列,这样每个位置第一次填数时(不管是第一个还是第二个排列)其贡献就确定了。
显然当前两个排列有用的信息仅仅是两个排列都填了、仅第一个排列填了、仅第二个排列填了、两个排列都没填的位置数量。并且注意到仅第一个排列填了和仅第二个排列填了的位置数量是相等的,同时dp过程中也知道当前填了多少个数,所以dp时只要记录两个排列都填了的位置数量即可。
于是设f[i][j][k]为填到i时,有j个位置两个排列都填了,当前贡献之和为k时的方案数,瞎转移即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 71 #define P 1000000007 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,f[N][N][N*N]; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} int C(int n,int m){return 1ll*n*(n-1)/2%P;} int main() { freopen("stat.in","r",stdin); freopen("stat.out","w",stdout); n=read(),m=read(); f[n+1][0][0]=1; for (int i=n+1;i>1;i--) { for (int x=0;x<=n+1-i;x++) { int y=n+1-i-x,z=n-x-y*2; if (y>=0&&z>=0) for (int k=0;k<=n*n;k++) if (f[i][x][k]) { if (z>=2) inc(f[i-1][x][k+(i-1)*2],1ll*f[i][x][k]*z%P*(z-1)%P); if (z>=1) inc(f[i-1][x+1][k+(i-1)],2ll*f[i][x][k]*z%P*y%P); if (z>=1) inc(f[i-1][x+1][k+(i-1)],1ll*f[i][x][k]*z%P); if (y>=1) inc(f[i-1][x+2][k],1ll*f[i][x][k]*y%P*y%P); } } } int ans=0; for (int i=m;i<=n*n;i++) inc(ans,f[1][n][i]); cout<<ans; return 0; }
以上是关于#189 stat(动态规划)的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 快速代码片段,用于在统计(阻止)/ dev / rdsk中的设备时验证fstat64和stat64的行为。