首页 > 其他 > 详细

那一天我们许下约定(背包dp)

时间:2019-07-20 19:46:54      阅读:108      评论:0      收藏:0      [点我收藏+]

内部题,题干不粘了。

$30分算法$


 首先看数据范围,可以写出来一个普通dp

技术分享图片
#include<bits/stdc++.h>
#define ll int
#define A 2100
#define mod 998244353
using namespace std;
ll f[1501][A+A+A],n,d,m;
int main()
{
    scanf("%d%d%d",&n,&d,&m);
    while(n!=0&&d!=0&&m!=0){
        memset(f,0,sizeof(f));
        f[0][0]=1;
        for(ll i=1;i<=d;i++)
        f[0][i]=1;
        for(ll i=1;i<=n;i++)
            for(ll k=1;k<=d;k++)
            {
                for(ll j=min(m-1,i);j>=0;j--)
                if(i-j>=0)    f[i][k]=(f[i][k]+f[i-j][k-1])%mod;
            }
        printf("%d\n",f[n][d]);
        scanf("%d%d%d",&n,&d,&m);
    }
}
View Code

d最大为$1e^12$所以你这个dp会完美T掉或者M掉

$100分算法$


 观察,发现n的范围非常小,m的范围也特别小。

所以我们利用这条性质,先片面的忽视掉这一天不给她饼干的情况,我们设定$f$定义为每天都给她饼干的情况。

设$f[i][j]$中i表示为前$i$天目前给了$j$个饼干的情况

然后可以推出来方程式

可以给她1~m-1个饼干

$f[i][j]=\sum_\limits {k=(j-M-1)}^{k<=j-1} f[i-1][k]$

然后直接转移,复杂度仍然难以接受,观察dp式子发现它是由一个字段转移过来的,我们要用前缀和维护优化一下。

仍然AC不了?

可能你会乘爆long long

注意多取模

技术分享图片
#include<bits/stdc++.h>
#define ll long long
#define  A 2010
#define mod 998244353
using namespace std;
ll f[A][A],n,m,q,d;
ll sum[A];
ll meng(ll x,ll k)
{
    ll ans=1;
    for(;k;k>>=1,x=x*x%mod)
        if(k&1)
            ans=x*ans%mod;
    return ans%mod;
}
int main(){
    
    while(1){
        scanf("%lld%lld%lld",&n,&d,&m);
        ll ans=0;
        if(n==0&&d==0&&m==0){
            return 0;
        }
        memset(f[1],0,sizeof(f[1]));
        f[0][0]=1;
        for(ll i=1;i<=min(n,m-1);i++)
            f[1][i]=1;
        for(ll i=2;i<=n;i++){
            for(ll j=0;j<=n;j++)
                sum[j]=(sum[j-1]%mod+f[i-1][j]%mod)%mod;
            for(ll j=1;j<=n;j++)
                f[i][j]=(sum[j-1]%mod-sum[max(j-m,0ll)]%mod+mod)%mod;
        }
        ll sd=d%mod;
        for(ll i=1;i<=min(n,d);i++)
        {
                if(i==1)
                    ans=(ans+sd*f[i][n]%mod)%mod,ans%=mod;
                else{
                    sd=(sd%mod*meng(i,mod-2)%mod*((d-i+1)%mod))%mod;
                    ans%=mod;
                    ans=(ans+f[i][n]%mod*sd%mod)%mod;
                }
//                if(sd!=0)printf("sd=%lld ans=%lld f*s=%lld\n",sd,ans,f[i][n]*sd%mod);
        } 
        cout<<(ans+mod)%mod<<endl;
    }
}
View Code

 

那一天我们许下约定(背包dp)

原文:https://www.cnblogs.com/znsbc-13/p/11218768.html

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