CF868F Yet Another Minimization Problem(决策单调性)
题目描述:给定一个序列,要把它分成k个子序列。每个子序列的费用是其中相同元素的对数。求所有子序列的费用之和的最小值。
输入格式:第一行输入n(序列长度)和k(需分子序列段数)。下一行有n个数,序列的每一个元素。
输出格式:输出一个数,费用和的最小值。
2<=n<=10^5,2<=k<=min(n,20),序列的每一个元素值大于等于1,小于等于n。
决策单调性到底是个什么神仙……
这题用分治做决策单调性……
问题是我连题解都看不懂……
米娜桑自己看题解吧,如果有会了的麻烦教我一下……->这里
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define ll long long 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 const int N=1e5+5; 20 int a[N],c[N],n,k; 21 ll ff[N],gg[N],*f=ff,*g=gg; 22 void solve(int l,int r,int kl,int kr,ll w){ 23 if(l>r) return; 24 int m=l+r>>1,k=0,p=m<kr?m:kr; 25 for(int i=l;i<=m;++i) w+=c[a[i]]++; 26 for(int i=kl;i<=p;++i) w-=--c[a[i]],g[m]>f[i]+w?g[m]=f[i]+w,k=i:0; 27 for(int i=kl;i<=p;++i) w+=c[a[i]]++; 28 for(int i=l;i<=m;++i) w-=--c[a[i]]; 29 solve(l,m-1,kl,k,w); 30 for(int i=l;i<=m;++i) w+=c[a[i]]++; 31 for(int i=kl;i<k;++i) w-=--c[a[i]]; 32 solve(m+1,r,k,kr,w); 33 for(int i=kl;i<k;++i) ++c[a[i]]; 34 for(int i=l;i<=m;++i) --c[a[i]]; 35 } 36 int main(){ 37 //freopen("testdata.in","r",stdin); 38 n=read(),k=read(); 39 ll *tmp; 40 for(int i=1;i<=n;++i) f[i]=f[i-1]+c[a[i]=read()]++; 41 memset(c,0,sizeof(c)); 42 while(--k){ 43 memset(g,1,(n+1)<<3); 44 solve(1,n,1,n,0); 45 tmp=f,f=g,g=tmp; 46 } 47 printf("%lld\n",f[n]); 48 return 0; 49 }
深深地明白自己的弱小