P11233 CSP-S 2024 染色

P11233 CSP-S 2024 染色

考试最后码方程忘记 a[i1] 了,调不出来,只好 50pts 收尾。

思路

dp 的难点在于确定一段的颜色后,无法快速找到上一段相同颜色的结尾。

从这里入手,设 dp[i][0/1][0/1] 表示第 i 位颜色为 1/0,第三维表示是一段颜色的 0 开头或 1 结尾。

sum[i][j][i,j] 为同一个颜色的得分,有递推式:

sum[i][j]=sum[i][j1]+(a[j1]==a[j])×a[j]

其中 i<jsum[i][i]=0

接下来考虑转移。

i 为一段颜色 0 的开头,[j,i1] 为一段颜色 1,那么上一段颜色 0 的结尾在 j1 处。之所以从 dp[j][1][0] 转移是因为需要加上 j 与上一段 1 结尾的贡献。

dp[i][0][0]=maxj<i(dp[j][1][0]+sum[j][i1]+(a[j1]==a[j])×a[i])

类似的,有:

dp[i][1][0]=maxj<i(dp[j][0][0]+sum[j][i1]+(a[j1]==a[i])×a[i])

i 为一段颜色 0 的结尾,这段颜色的开头 j 可以是 [1,i] 中任意一个点。

那么有 dp[i][0][1]=maxji(dp[j][0][0]+sum[j][i])

类似的 dp[i][1][1]=maxji(dp[j][1][0]+sum[j][i])

观察 sum 的求法,发现本质上可以前缀和作差优化。

重新设 sum[i][1,i] 的颜色相同贡献,[l,r] 颜色相同的贡献等于 sum[r]sum[l]

方程变为:

dp[i][0][0]=maxj<i(dp[j][1][0]sum[j]+(a[j1]==a[j])×a[i])+sum[i1]

dp[i][0][1]=maxji(dp[j][0][0]sum[j])+sum[i]

剩下两条与上面方程类似,就不写了。

对于方程 dp[i][0][1]dp[j][0][0]sum[j] 中取一个最大值可以 O(1) 的实现,对于另一个,发现难点在于 a[j1]a[i] 颜色相同时会产生一个 a[i] 的贡献。

那么先对于所有的 j 都不加 a[j1]a[i] 的贡献求一个 dp[j][1][0]sum[j] 的最大值,同时在 a[j1]a[i] 相同的 j 里也求一个 dp[j][1][0]sum[j] 的最大值,最后将后一个的最大值加 a[i] 与前一个最大值比较,便可以得出 dp[i][0][0] 的最终答案。

最后答案时 max(dp[n][0][1],dp[n][1][1])

Ps:其实你发现第 3 维的作用仅限于统计答案,所以其实可以去掉。

具体操作看实现,时间复杂度 O(n)

CODE

#include<bits/stdc++.h>
using namespace std;

#define ll long long

const int maxL=1e6+5,maxn=2e5+5;

int n;
int a[maxn];

ll cho[maxL][2],acl[2],sum[maxn],dp[maxn][2][2];

int main()
{
    // freopen("color2.in","r",stdin);
    // freopen("color.out","w",stdout);
    int _;
    scanf("%d",&_);
    while(_--)
    {
        memset(cho,-0x3f,sizeof(cho));
        memset(acl,0,sizeof(acl));
        memset(sum,0,sizeof(sum));
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(a[i-1]==a[i])*a[i];
        for(int i=1;i<=n;i++)
        {
            dp[i][0][0]=max(acl[1]+sum[i-1],cho[a[i]][1]+sum[i-1]+a[i]);
            dp[i][1][0]=max(acl[0]+sum[i-1],cho[a[i]][0]+sum[i-1]+a[i]);
            acl[0]=max(acl[0],dp[i][0][0]-sum[i]);
            acl[1]=max(acl[1],dp[i][1][0]-sum[i]);
            cho[a[i-1]][1]=max(cho[a[i-1]][1],dp[i][1][0]-sum[i]);
            cho[a[i-1]][0]=max(cho[a[i-1]][0],dp[i][0][0]-sum[i]);
            dp[i][0][1]=acl[0]+sum[i];
            dp[i][1][1]=acl[1]+sum[i];
        }
        printf("%lld\n",max(dp[n][0][1],dp[n][1][1]));
    }
}

后记

去年忘记加 1 少 100pts,今年忘记 150pts……

posted @   彬彬冰激凌  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示