1. 程式人生 > >12.25模擬賽T1

12.25模擬賽T1

 

可以區間dp,但是複雜度太高。

所以應該是貪心,怎麼貪心呢?

這種題目,最好還是手玩找一些規律。

可以發現,由於保證可以m次填完,所以顏色之間沒有相互包含關係。

比較像分治的模型。

所以考慮拿到一個區間怎麼處理。

假設a[l]==a[r],那麼為了合法,一定先刷這種顏色。然後分部分遞迴下去。

否則,對於區間:AEEGEABBBCDDC

裡面的夾心肯定不能先處理了,可以大概看做:A..AB..BC..C

先刷哪一個?

刷兩邊長度較小的一個

證明:

如果刷中間,那麼中間的位置之後就不能再動了。如果刷比較長的一個,那麼之後不能再動。

如果刷比較短的一個,長的可以再多刷幾次,貢獻更大。

比較即可。(如果兩邊長度相同,比較下一個。)

O(m^2+n)

理論上可以後綴陣列優化到:O(mlogn+n)

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true
); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=1e5; const int M=5005; int st[M],nd[M]; ll ans; int a[N]; int n,m; vector<int>mem[M]; void sol(int l,int r){ //cout<<" sol "<<l<<" "<<r<<" "<<ans<<endl;
if(l>r) return; if(l==r){ ++ans;return; } if(a[l]==a[r]){ ans+=r-l+1; int las=l; for(reg i=1;i<mem[a[l]].size();++i){ sol(las+1,mem[a[l]][i]-1); las=mem[a[l]][i]; } } else{ int L=l,R=r; int go=0; ans+=r-l+1; while(!go){ if(nd[a[L]]-st[a[L]]+1<nd[a[R]]-st[a[R]]+1){ go=l;break; }else if(nd[a[L]]-st[a[L]]+1>nd[a[R]]-st[a[R]]+1){ go=r;break; } L=nd[a[L]]+1;R=st[a[R]]-1; if(L>R) go=l; } if(go==l){ int las=l; for(reg i=1;i<mem[a[l]].size();++i){ sol(las+1,mem[a[l]][i]-1); las=mem[a[l]][i]; } sol(las+1,r); }else{ int las=st[a[r]]; for(reg i=1;i<mem[a[r]].size();++i){ sol(las+1,mem[a[r]][i]-1); las=mem[a[r]][i]; } sol(l,st[a[r]]-1); } } } int main(){ rd(n);rd(m); for(reg i=1;i<=n;++i){ rd(a[i]); if(st[a[i]]==0) st[a[i]]=i; nd[a[i]]=i; mem[a[i]].push_back(i); } sol(1,n); printf("%lld",ans); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/12/25 15:04:11 */

總結:

沒有想到的原因是,還是沒有從手玩找規律這個方向入手。

對於一些沒有什麼思路的題,可以嘗試“不完全歸納”

其實規律還是比較簡單的。