zoukankan      html  css  js  c++  java
  • Codeforces 1322D

    Codeforces 题面传送门 & 洛谷题面传送门

    首先这个消消乐的顺着消的过程看起来有点难受,DP 起来有点困难。考虑对其进行一个转化:将所有出场的人按照攻击力从小到大合并,然后每次将两个攻击力为 (l) 的合并为一个攻击力为 (l+1) 的人,答案加上 (c_{l+1}),如果发现攻击力为 (l) 的人 (le 1) 那就继续合并攻击力为 (l+1) 的人,不难发现这个过程与原题的过程等价。

    接下来考虑如何 DP 求解原问题。我们将序列翻转,这样单调不减就可以转化为单调不升,方便我们的合并过程。设 (dp_{x,i,j}) 表示当前考虑了前 (x) 个人,合并到攻击力 (=i) 的人,目前攻击力 (=i) 的人有 (j) 个,转移就新加入一个人时,令 (dp_{x,l_x,j+1}leftarrow dp_{x-1,l_x,j}-s_x+c_{l_x}),然后从 (l_x) 开始往 (n) 枚举更新合并的贡献即可,具体来说 (dp_{x,i+1,j/2}leftarrow dp_{x,i,j}+dfrac{j}{2}·c_{i+1})。你可能会疑惑为什么不直接一次性合并完所有攻击力为 (i) 的人直到不能合并为止,这是因为你有可能出现合并到一半又进来了新的人的情况,这种情况下就要一步步合并。(x) 那一维可以去掉这样空间复杂度可以达到平方。直接转移单次复杂度是 (n^2) 的,总复杂度 (n^3),无法通过。不过注意到在合并的过程中,我们的 (j) 只可能达到 (dfrac{x}{2^{i-l_x}}),因此 (j) 的枚举只用枚举到 (dfrac{x}{2^{i-l_x}}) 即可,这样总复杂度就是平方。

    const int MAXN=2000;
    int n,m,l[MAXN+5],s[MAXN+5],dp[MAXN*2+5][MAXN+5],c[MAXN*2+5];
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",&l[i]);
    	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    	for(int i=1;i<=n+m;i++) scanf("%d",&c[i]);
    	memset(dp,192,sizeof(dp));
    	for(int i=1;i<=n+m;i++) dp[i][0]=0;
    	for(int i=n;i;i--){
    		for(int j=n;j;j--) chkmax(dp[l[i]][j],dp[l[i]][j-1]+c[l[i]]-s[i]);
    		for(int j=l[i];j<=n+m;j++) for(int k=0;k<=(n>>(j-l[i]));k++)
    			chkmax(dp[j+1][k>>1],dp[j][k]+1ll*(k>>1)*c[j+1]);
    	} printf("%d
    ",dp[n+m][0]);
    	return 0;
    }
    
  • 相关阅读:
    .NET 4.0 中的契约式编程
    DELL安装Windows Server 2019
    Mysql 5.7.34免安装版本
    MQTT
    WPF属性
    WPF数据绑定
    git系列之(五)git stash 命令
    Vue.js
    git 对比两个分支差异
    TPL 之二 TransformBlock
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1322D.html
Copyright © 2011-2022 走看看