DP搬運工1
阿新 • • 發佈:2020-08-17
D. DP搬運工1
記憶體限制:512 MiB 時間限制:1000 ms 輸入檔案:D.in 輸出檔案:D.out 題目型別:傳統 評測方式:文字比較題目描述
給你n,k,求有多少個1到n的排列,滿足相鄰兩個數的max的和不超過。
輸入格式
一行兩個整數n,k。
輸出格式
一行一個整數ans表示答案mod 998244353。
樣例
樣例輸入1
4 10
樣例輸出1
16
樣例輸入2
10 66
樣例輸出2
1983744
資料範圍與提示
有50個測試點,第i個測試點為n=i,k<=$n^2$。
思路:
題外話:一般來說,會先設f[i][j]表示前i個數max的和為j的方案數,但轉移時因為不知道第i+1個數放在哪,所以會有後效性,不可行。
題解:根據上面錯誤的思路,可以加以為則$f[i][j][k]$表示前i個數,在放入前$i$個數後還有$j$個位置,$max$和為k的方案數。
當i+1要放在這些數之間時,若i+1旁邊能放兩個數,則貢獻為0;若i+1旁邊能放一個數,貢獻為i+1;若一個數也不能放,則貢獻為i+1+i+1;
當i+1放兩邊時,同上
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll;//注意強轉long longView Code6 const int maxn=50+5,mod=998244353; 7 int f[maxn][maxn*maxn],g[maxn][maxn*maxn]; 8 int main(){ 9 int n,k; 10 scanf("%d%d",&n,&k); 11 f[0][0]=1;//初始化是針對i==1時 12 for(int i=2;i<=n;i++){//注意i應從2開始,因為初始化針對1 13 memcpy(g,f,sizeof(f));//g儲存i-1的資訊 14 memset(f,0,sizeof(f));15 for(int j=0;j<=n-i+1;j++){//因為g儲存i-1的資訊,j<=n-(i-1) 16 for(int m=0;m<=k;m++){ 17 int x=g[j][m]; 18 if(!x) continue; 19 if(j)f[j][m+i]=(ll)(f[j][m+i]+(ll)2*x*j)%mod; 20 if(j)f[j+1][m]=(ll)(f[j+1][m]+(ll)x*j)%mod; 21 if(j)f[j-1][m+i+i]=(ll)(f[j-1][m+i+i]+(ll)x*j)%mod; 22 f[j][m+i]=(ll)(f[j][m+i]+(ll)2*x)%mod; 23 f[j+1][m]=(ll)(f[j+1][m]+(ll)2*x)%mod; 24 } 25 } 26 } 27 int ans=0; 28 for(int i=0;i<=k;i++) ans=(ans+f[0][i])%mod; 29 printf("%d\n",ans); 30 return 0; 31 }