[题解]P11233 [CSP-S 2024] 染色
设\(f[i][j=0/1]\)表示涂到第\(i\)位,且第\(i\)为颜色为\(j\),则考虑用\(i\)之前能和\(i\)匹配的位置\(p\)进行转移。\(p\)需要满足下面的条件:
- \(a[p]=a[i]\)。
- \(p\)的颜色为\(j\)。
- \([p+1,i-1]\)之间的颜色全不为\(j\)。
显然,我们只需要找满足条件的最大\(p\)即可,否则答案一定不是最优。所以我们直接维护\(lst[i]=p\)为\(i\)前面满足条件\(1\)的最大,要想满足条件\(3\),我们还需要维护\(g[l][r]\)表示\(l,r\)这个区间全部同色时,该区间的答案,具体求法:
然后有\(f\)的转移(\(p\neq 0\)时):
为什么是\(f[p+1]\)而不是\(f[p]\)?因为如果用\(f[p]\)来转移,就不能制约\([p+1,i-1]\)的颜色和\(i,p\)不同了。
然后可以注意到\(0\)和\(1\)是对称的,所以砍掉第二维是可以的。
点击查看代码
#include<bits/stdc++.h> #define N 200010 using namespace std; int t,n,a[N],lst[N],f[N],g[2002][2002]; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr),cout.tie(nullptr); cin>>t; while(t--){ memset(lst,0,sizeof lst); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ g[i][j]=g[i][j-1]+a[j]*(a[j-1]==a[j]); } } for(int i=1;i<=n;i++){ f[i]=f[i-1]; if(lst[a[i]]) f[i]=max(f[i],f[lst[a[i]]+1]+a[i]+g[lst[a[i]]+1][i-1]); lst[a[i]]=i; } cout<<f[n]<<"\n"; } return 0; }
时空复杂度都是\(O(n^2)\)的,瓶颈在于预处理\(g\)。不难发现可以只保留\(g[0]\)作为\(sum\),然后用前缀和的思想,将\(g[x][y]\)转为\(sum[y]-sum[x]\)即可。这是因为区间同色必须要求匹配的位置连续,而\(sum[x]\)表示\((1,2)\sim(x-1,x)\)的答案,\(sum[y]\)则表示\((1,2)\sim(y-1,y)\)的答案,两者相减就是\((x,x+1)\sim(y-1,y)\)的答案。
注意\(lst[i]=i-1\)时,区间会出现\(x>y\)的情况,此时注意与\(0\)取\(\max\)。
时空复杂度都为\(O(n)\)。
点击查看代码
#include<bits/stdc++.h> #define int long long #define V 1000010 #define N 200010 using namespace std; int t,n,a[N],lst[V],f[N],g[N]; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr),cout.tie(nullptr); cin>>t; while(t--){ memset(lst,0,sizeof lst); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=2;i<=n;i++) g[i]=g[i-1]+a[i]*(a[i-1]==a[i]); for(int i=1;i<=n;i++){ f[i]=f[i-1]; if(lst[a[i]]){ f[i]=max(f[i],f[lst[a[i]]+1]+a[i]+max(g[i-1]-g[lst[a[i]]+1],0ll)); } lst[a[i]]=i; } cout<<f[n]<<"\n"; } return 0; }
第\(19\)行,PassName的题解用
f[i]=max(f[i],f[lst[a[i]]+1]+a[i]+g[i]-g[lst[a[i]]+1]);
代替了
f[i]=max(f[i],f[lst[a[i]]+1]+a[i]+max(g[i-1]-g[lst[a[i]]+1],0ll));
这样也是可以的,因为:
- 当\(a[i]=a[i-1]\)时,\(g[i]-g[lst[a[i]]+1]=g[i]-g[i]=0\),而\(g\)是单调不降的,所以\(g[i-1]-g[lst[a[i]]+1]\le 0\),取\(\max\)后同样\(=0\)。
- 当\(a[i]\neq a[i-1]\)时,又有\(g[i]=g[i-1]\),又\((lst[a[i]]+1)\le (i-1)\),所以\(g[lst[a[i]]+1]\le g[i-1]\),自然两式也相等。
感谢hanss6在此写法的理解上给我的帮助。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战