CF1416E-Split【dp,set】
正題
題目鏈接:https://www.luogu.com.cn/problem/CF1416E
題目大意
給出nnn個正整數的一個序列aia_iai?,你要把aia_iai?拆成兩個正整數的和b2i,b2i+1b_{2i},b_{2i+1}b2i?,b2i+1?,要求使得bbb的相同連續段最少。
1≤n≤5×105,1≤ai≤1091\leq n\leq 5\times 10^5,1\leq a_i\leq 10^91≤n≤5×105,1≤ai?≤109
解題思路
考慮求最大的相鄰相同數目,先考慮暴力的dpdpdp,設fi,jf_{i,j}fi,j?表示分解完aia_iai?且b2i+1=jb_{2i+1}=jb2i+1?=j時的方案,那么有轉移方程
fi,j=max?{fi?1,k+[k=ai?j]}+[2j=ai]f_{i,j}=\max\{f_{i-1,k}+[k=a_i-j]\}+[2j=a_i]fi,j?=max{fi?1,k?+[k=ai??j]}+[2j=ai?]
而且不難發現對于一個iii來說它的所有fi,jf_{i,j}fi,j?在加上[2j=ai][2j=a_i][2j=ai?]之前差距不會超過111,而且我們顯然只有可能從最大值轉移。
對于2j=ai2j=a_i2j=ai?的情況很難處理,我們可以先考慮都是奇數的情況。
首先開始都有f1,j=0f_{1,j}=0f1,j?=0,可以記為區間[1,a1?1][1,a_{1}-1][1,a1??1],然后到第二個對于一個最大的jjj,我們可以轉移到a2?ja_2-ja2??j(如果合法)。同樣的我們可以翻轉之后得到一個新的最大區間[l,r][l,r][l,r],當某次之后這個區間空了那么因為上面提到的fi,jf_{i,j}fi,j?的差距不會超過111,所以最大值不變然后區間變回[1,ai?1][1,a_{i}-1][1,ai??1]。
之后考慮aia_iai?有偶數的情況怎么處理,此時會出現的問題就是:如果ai2\frac{a_i}{2}2ai??加之前是最大值,那么加上之后就變為了唯一的最大值,這個很好處理,而如果之前不是最大值,那么加了之后就變為了最大值。
這個時候有可能會在區間之外出現一些單點的最大值,我們可以用setsetset來儲存這些位置,至于翻轉之后所有的位置xxx都會變為ai?xa_i-xai??x,那么可以儲存一個xxx表示實際上這個位置的值為x×f+bufx\times f+bufx×f+buf的情況,這樣我們就可以快速的翻轉然后把不合法的值去掉就好了。
時間復雜度:O(nlog?n)O(n\log n)O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<set> #define ll long long using namespace std; const ll N=5e5+10; ll T,n,ans,l,r,flag,f,buf,a[N]; set<ll> s; void solve(ll lim){flag=1;if(l<=r){if(lim<=l)l=1,r=0;else l=lim-l,r=lim-min(r,lim-1),swap(l,r),flag=0;}f=f*-1;buf=lim-buf;while(!s.empty()){ll w=(*s.begin())*f+buf;if(w<1||w>=lim)s.erase(s.begin());else break;}while(!s.empty()){ll w=(*(--s.end()))*f+buf;if(w<1||w>=lim)s.erase(--s.end());else break;}return; } signed main() {scanf("%lld",&T);while(T--){s.clear();f=ans=1;buf=flag=0;scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);if(a[1]&1)l=1,r=a[1]-1,ans++;else l=r=a[1]/2;for(ll i=2;i<=n;i++){ // if(s.size())printf("%d\n",*s.begin());if(a[i]&1){solve(a[i]);ans++; if(s.empty()&&flag)l=1,r=a[i]-1,ans++;}else{if(s.find((a[i]/2-buf)*f)!=s.end()||a[i]/2>=l&&a[i]/2<=r)s.clear(),l=r=a[i]/2;else solve(a[i]),s.insert((a[i]/2-buf)*f),ans++;}}printf("%lld\n",ans);}return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的CF1416E-Split【dp,set】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无线路由器桥接后怎么二级路由link无线
- 下一篇: 音乐剪辑怎么弄电脑如何剪辑音乐软件