7.19T1

现在的我是T2一点头绪都搞不到(然而大家都快要A掉它了,我还处在M0的状态),T3只能摸到个大体思路,但是还是模模糊糊的,决定写点题解,冷静一下

通过T1部分分式子的过程,让我意识到对于一道明确的DP题,一定要在算草纸上写一写,推一推,你可以列出来你有什么,你需要什么,然后去依据DP的实际意义进行拼凑,当然对自己DP式子的不断优化也是需要的

30分其实很好拿,我们设定$dp[i][j]$代表到第$i$天还剩下$j$块饼干没有被分出去,那么这个$i$应该属于$[1,d]$,那很容易可以想到$dp[i][j]+={\sum}dp[i-1][k]$,$k$属于$[j,j+m-1]$,那应该在优化时可以想到这个$\sum$可以用前缀和搞定,关于初始化令$dp[0][n]=1$然后处理一下前缀和就可以了

但实际上我们很容易就能够看出这个想法的不足之处,比如你的第一维要循环$d$,不论时间会不会炸,空间一定是炸了,并且是根本开不到的那种,但是你会发现$n$其实算的上很小,而且对于$d$远大于$n$的情况,一定是有很多天都没有给饼干,那我们完全就可以把这些什么都没有给出的天从$dp$中除名,这样的话空间,时间复杂度都可以降下来很多,那我们就重新来定义$dp[i][j]$的含义,我们用$dp[i][j]$来表示,已经给出去饼干$i$天(给出去饼干就代表饼干数不为0),一共给出去$j$块饼干,我们模仿着刚才的思路,依旧可以写出来一个前缀和优化过的DP式子,$dp[i][j]=sum[i-1][j]-sum[i-1][j-m]$,其实这个东西是在可想的范围内的,但是我没想啊,那能有什么办法,怪自己呗

关于这个$sum[i-1][j-m]$一定要注意一下$j-m$是不是小于0了,最好还是不要下标越界,关于取模,只要你对自己的时间复杂度足够自信,那你就随便模,如果有做减法的情况,一定要先加一个模数,免得出现负数,在这里在给一个小建议,如果不知道自己会不会得到什么奇奇怪怪的负数,那就自己去造几组比较大的数据,没有暴力的话,没办法看对错,但是如果出现负数了,证明你肯定不对

最后的$ans={\sum}dp[i][n]{\times}C_d^i$,在我们对$C$进行计算的时候会发现不论是$Lucas$还是杨辉三角打表,下标为$d$都不是可用的好方法,那我们思考一下$C_n^m=\frac{n!}{m!{\times}(n-m)!}$,我们进行一下简单的消项,那$C_n^m=\frac{n{\times}(n-1){\times}{\cdots}{\times}(n-m+1)}{m!}$,那对于分母上m!我们可以求一下逆元,对于分子那一大坨,因为$i$每次之加一,完全可以递推$O(1)$实现,这样的话我们不仅解决了这道题,还得到了一个求C的新思路

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define ll long long
 5 #define maxn 2010
 6 using namespace std;
 7 const long long mod=998244353;
 8 int n,m;
 9 ll d,ans;
10 ll jc[maxn],ny[maxn];
11 ll dp[maxn][maxn],sum[maxn][maxn];
12 ll ksm(ll a,ll b)
13 {
14     ll ans=1;  a=a%mod;
15     while(b>0)
16     {
17         if(b&1)  ans=(ans*a)%mod;
18         b=b>>1;  a=(a*a)%mod;
19     }
20     return ans%mod;
21 }
22 void clear()
23 {
24     memset(dp,0,sizeof(dp));  memset(sum,0,sizeof(sum));
25     memset(jc,0,sizeof(jc));  memset(ny,0,sizeof(ny));
26     ans=0;  dp[0][0]=1;  jc[0]=1;
27     for(int i=0;i<=n;++i)  sum[0][i]=1;
28     for(int i=1;i<=n;++i)  jc[i]=(jc[i-1]*i)%mod;
29     ny[n]=ksm(jc[n],mod-2);
30     for(int i=n;i>=1;--i)  ny[i-1]=(ny[i]*i)%mod;
31 }
32 int main()
33 {
34     while(1)
35     {
36         scanf("%d%lld%d",&n,&d,&m);
37         if(n==0&&d==0&&m==0)  break;
38         if(d*(ll)m<(ll)n)  {printf("0\n");  continue;}
39         clear();
40         for(int i=1;i<=min((ll)n,d);++i)
41         {
42             for(int j=i;j<=n;++j)
43             {
44                 if(j-m<0)
45                 {
46 //                    cout<<"j-m="<<j-m<<endl;
47 //                    cout<<"sum["<<i-1<<"]["<<j-1<<"]="<<sum[i-1][j-1]<<" ";
48                     dp[i][j]=sum[i-1][j-1];
49 //                    cout<<"dp["<<i<<"]["<<j<<"]=sum["<<i-1<<"]["<<j-1<<"]"<<" ";
50 //                    if(dp[i][j]<0)  cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<endl;
51                 }
52                 else
53                 {
54 //                    cout<<"sum["<<i-1<<"]["<<j-1<<"]="<<sum[i-1][j-1]<<" ";
55 //                    cout<<"sum["<<i-1<<"]["<<j-m<<"]="<<sum[i-1][j-m]<<" ";
56                     dp[i][j]=(sum[i-1][j-1]-sum[i-1][j-m]+mod)%mod;
57 //                    cout<<"dp["<<i<<"]["<<j<<"]=sum["<<i-1<<"]["<<j-1<<"]-";
58 //                    cout<<"sum["<<i-1<<"]["<<j-m<<"]"<<" ";
59 //                    if(dp[i][j]<0)  cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<endl;
60                 }
61                 sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
62 //                if(sum[i][j]<0)  cout<<"sum["<<i<<"]["<<j<<"]="<<sum[i][j]<<endl;
63             }
64         }
65         ll ls=d%mod;
66         for(int i=1;i<=min((ll)n,d);++i)
67         {
68             ll zhs=ny[i];
69             if(i!=1)  ls=(ls*(d%mod-(ll)i+(ll)1)%mod)%mod;
70             zhs=(zhs*ls)%mod;
71 //            for(int j=d-i+1;j<=d;++j)  zhs=(zhs*j)%mod;
72 //            cout<<"C("<<d<<","<<i<<")="<<zhs<<endl;
73             ans=(ans+(dp[i][n]*zhs)%mod)%mod;
74 //            if(ls<0)  cout<<ls<<endl;
75         }
76 //        for(int i=1;i<=min((ll)n,d);++i)
77 //            for(int j=0;j<=n;++j)  cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<endl;
78 //        for(int i=1;i<=((ll)n,d);++i)
79 //            for(int j=0;j<=n;++j)  cout<<"sum["<<i<<"]["<<j<<"]="<<sum[i][j]<<endl;
80 //        while(ans<0)  ans=ans+mod;
81         printf("%lld\n",ans%mod);
82     }
83     return 0;
84 }
调试略显丑陋

 

posted @ 2019-07-21 06:20  hzoi_X&R  阅读(123)  评论(0编辑  收藏  举报