這個題呢,一開始是用DP想的,但是沒有按照DP的思路走,因為題目意思描述得很簡單,顯然是可以打表找規律的
先附上打表的程式
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
int dp[10][10],n;
int num[10];
bool vis[10];
void calc(){
//for(int i=1;i<=n;i++)
// printf("%d%c",num[i],i==n?'\n':' ');
int res=0;
for(int i=1;i<=n;i++)
if (num[i]>i) res++;
dp[n][res]++;
}
void dfs(int step){
if (step>n) calc();
for(int x=1;x<=n;x++)
if (!vis[x]){
num[step]=x;
vis[x]=true;
dfs(step+1);
vis[x]=false;
}
}
int main(){
n=7;
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
dfs(1);
for(int i=0;i<=n;i++)
printf("%d%c",dp[n][i],i==n?'\n':' ');
return 0;
}
代碼就是用dfs生成了所有的排列,然後根據題意統計,dp【i】【j】:有i個數字,j個根據題意的比對
我們可以修改n,n=3,4,5,6,7,8,……這些小資料打出來一個表,然後可以來找規律(這是一種可行的方法)
但是dp的方法呢,來遞推公式:
dp【i】【j】會怎麼來:
第一部分:dp【i-1】【j】,最大的第i個數放在最後面
第二部分:dp【i-1】【j】*j,最大的第i個數與前i-1個數字中的j個比原來位置上的數大的數互換位置,比對值不變
第三部分:dp【i-1】【j-1】*(i-1-(j-1)),因為要增加一個比對,就不能在原來已經有比對的位置上選擇
代碼:
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define ll long long
const int maxn=1010;
ll dp[maxn][maxn];
const int mod=1e9+7;
int main(){
//freopen("input.txt","r",stdin);
memset(dp,0,sizeof(dp));
for(int i=1;i<=1000;i++){
dp[i][0]=1;
for(int j=1;j<=i;j++)
dp[i][j]=(dp[i-1][j]*(j+1)+dp[i-1][j-1]*(i-j))%mod;
}
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
printf("%lld\n",dp[n][k]);
return 0;
}