一些dp题

ABC192F

(真的只有绿吗)

首先,很明显有,其中S代表初始魔力值,k为选择的物品数量,x为题目中给定的

然后注意到x很大,但k和n很小,所以我们可以设定状态,表示当前到第i个物品,已经选了j个,总和模k为l,这么选的初始魔法最大值(显然初始魔法越大时间花费越少),然后暴力枚举选的总数量并转移即可,时间复杂度

(oi的精髓在于枚举与模拟)

点击查看代码
void solve() {
    cin>>n>>x;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int k=1;k<=n;k++) {
        for(int i=0;i<=n+2;i++)
            for(int j=0;j<=n+2;j++)
                for(int l=0;l<=k;l++) dp[i][j][l]=0;
        for(int i=1;i<=n;i++) { 
            dp[i][1][a[i]%k]=a[i];
            for(int j=1;j<=n;j++) 
                for(int l=0;l<k;l++) 
                    mx(dp[i][j][l],dp[i-1][j][l],dp[i-1][j-1][(l-a[i]%k+k)%k]==0?-inf:dp[i-1][j-1][(l-a[i]%k+k)%k]+a[i]);    
        } if(dp[n][k][x%k]) ans=min(ans,(x-dp[n][k][x%k])*1ll/k);
    } printf("%lld",ans);
}

ABC134F

这个题花了很久才看明白怎么做,感觉题解写的很奇怪

首先,看到这个绝对值,我们很自然想到拆贡献,我们把第i位上填称为i与相匹配,那么一个数的贡献只与其匹配的数相关

具体地,先考虑每个i,如果与其匹配的数比它大,将绝对值拆开后i的贡献会变成-i,反之则是i,同理

所以单看每个数对奇怪度的贡献,只需要讨论它和匹配数的大小关系

我们把i和全放在一起考虑,可以设出一个状态表示当前考虑到第i位,前面有j个i和未匹配(它们未匹配的数量肯定相同),当前奇怪度为k

怎么转移呢?

首先,第i位上可以填i,此时贡献为0,有
fi,j,k=fi1,j,k

然后,可以两个都与后面进行匹配,这时它们是比后面的数小,所以是正贡献

fi,j,k=fi1,j1,k+2×i

两个数也可以与前面的数匹配,此时是负贡献

fi,j,k=fi1,j+1,k2×i×(j+1)

也可以一个与前面匹配,一个与后面匹配,注意方案要乘2

fi,j,k=fi1,j,k×2

最后注意奇怪度可以减成负数,我的处理是直接在k维上加了n*n

点击查看代码
void solve() {
    cin>>n>>m;  ll maxn=n*n*2; dp[0][0][n*n]=1;
    for(int i=1;i<=n;i++) {
        for(int j=0;j<=i;j++) {
            for(int k=0;k<=maxn;k++) {
                add(dp[i][j][k],dp[i-1][j][k]);
                if(j) add(dp[i][j][k],dp[i-1][j][k]*2ll*j%M);
                if(j&&k+i*2<=maxn) add(dp[i][j][k],dp[i-1][j-1][k+2*i]);
                if(j<i-1&&k-i*2>=0) add(dp[i][j][k],dp[i-1][j+1][k-2*i]*(j+1)*1ll*(j+1)%M);
            } 
        } 
    } 
    printf("%lld",dp[n][0][m+n*n]);
}
posted @ 2025-10-03 14:03  he_qwq  阅读(4)  评论(0)    收藏  举报