删数

NOIP T3!!!序列先看看差分数组!!!

A. 删数

Solution 考虑操作本质上就是合并 2 个相邻且相同的差分数组,那么对于一个差分值 x,合成到最后一定是 x2k,考虑 dp,设 f[i] 表示差分数组 [1,i] 最少留下几个数,考虑以 i 倍增去跳,即 map[i][a[i]] 表示以 i 为右端点合并到最后的差分值是 a[i] 所在的左端点(开)。用 map 记录下即可。

http://pjudge.ac/submission/25713

#include <bits/stdc++.h> using namespace std; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } const int N=(int)(3e5+5); map<int,int>mp[N]; int n,a[N],d[N],f[N]; void solve() { n=rd(); for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<n;i++) d[i]=a[i+1]-a[i]; --n; for(int i=0;i<=n;i++) f[i]=(int)(2e9),mp[i].clear(); f[0]=0; for(int i=1;i<=n;i++) { int y=i-1; int x=d[i]; mp[i][x]=i-1; //这里是开的 f[i]=f[i-1]+1; while(1) { auto qwq=mp[y].find(x); if(qwq==mp[y].end()) break ; y=(*qwq).second; x*=2; f[i]=min(f[i],f[y]+1); mp[i][x]=y; } } // f[i] 代表的是 差分数组 [1,i] 最少剩下多少个,所以最后原序列答案+1 printf("%d\n",f[n]+1); } signed main() { int T=rd(); while(T--) solve(); return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/16098531.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示