[题解]P3147 [USACO16OPEN] 262144 P
P3146 [USACO16OPEN] 248 G(弱化版)
我们先考虑区间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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效