首页 > 其他 > 详细

DP搬运工1

时间:2020-08-17 22:34:15      阅读:84      评论:0      收藏:0      [点我收藏+]

                                                     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 long 
 6 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 }
View Code

 

DP搬运工1

原文:https://www.cnblogs.com/HZOIDJ123/p/13520000.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!