可以区间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 */
总结:
没有想到的原因是,还是没有从手玩找规律这个方向入手。
对于一些没有什么思路的题,可以尝试“不完全归纳”
其实规律还是比较简单的。