[题解]P3147 [USACO16OPEN] 262144 P

P3146 [USACO16OPEN] 248 G(弱化版)

P3147 [USACO16OPEN] 262144 P

我们先考虑区间dp,设\(f[i][j]\)表示\(a[i,j]\)恰好合并成\(1\)个元素后的答案,\(0\)表示无法合并。

那么对于\(k\)使得\(f[i][k]=f[k+1][j]\neq 0\),有转移\(f[i][j]=f[i][k]+1\)

有结论:对于可以合并的区间\([l,r]\),它们能合并出的答案是唯一的。

\(\bf{Proof}\):可以将每个值\(a[i]\)映射到\(b[i]=2^{a[i]}\),合并相当于同指数相加,所以\(b\)的最终合并答案固定为\(2^x\),那么\(a\)的答案固定为\(x\)

根据此结论,只要找到一个\(k\)满足条件,直接更新并break出去就可以,不需要对所有\(k\)\(\max\)

时间复杂度\(O(n^3)\),可以通过弱化版。

点击查看代码
#include<bits/stdc++.h>
#define N 250
using namespace std;
int n,a[N],f[N][N],ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],f[i][i]=a[i];
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
if(f[i][k]==f[k+1][j]&&f[i][k]){
f[i][j]=f[i][k]+1;
break;
}
}
ans=max(ans,f[i][j]);
}
}
cout<<ans<<"\n";
return 0;
}

根据上面的结论,可以推得:对于一个左端点\(l\),如果存在右端点\(r\),使得\(a[l,r]\)可以合并成整数\(k\),那么这个右端点\(r\)是唯一的。又受上面用二进制思考的证明的启发,我们采用倍增。

\(f[i][j]\)表示以\(i\)为左端点合并成\(j\)这个答案的右端点\(+1\)是多少,\(0\)表示不存在右端点。

有转移\(f[i][j]=f[f[i][j-1]][j-1]\),很纯的倍增。

代码中循环跑到了\(58\),是因为答案最大就是\(58\),因为\(262144=2^{18}\),最极端的情况就是所有元素都是\(40\),此时答案是\(40+18=58\)。所以时间复杂度是\(O(n(\log n+V))\)的。

点击查看代码
#include<bits/stdc++.h>
#define N 262150
#define V 60
using namespace std;
int n,a[N],f[N][V],ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],f[i][a[i]]=i+1;
for(int i=2;i<=58;i++){
for(int j=1;j<=n;j++){
if(!f[j][i]) f[j][i]=f[f[j][i-1]][i-1];
if(f[j][i]) ans=i;
}
}
cout<<ans<<"\n";
return 0;
}
posted @   Sinktank  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2025-3-6 6:10:33 TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.
点击右上角即可分享
微信分享提示