1. 程式人生 > >[BZOJ1584]Cleaning Up 打掃衛生

[BZOJ1584]Cleaning Up 打掃衛生

Description

有N頭奶牛,每頭那牛都有一個標號Pi,1 <= Pi <= M <= N <= 40000。現在Farmer John要把這些奶牛分成若干段,定義每段的不河蟹度為:若這段裡有k個不同的數,那不河蟹度為k*k。那總的不河蟹度就是所有段的不河蟹度的總和。

Input

第一行:兩個整數N,M

第2..N+1行:N個整數代表每個奶牛的編號

Output

一個整數,代表最小不河蟹度

Sample Input

13 4
1
2
1
3
2
2
3
4
3
4
3
1
4

Sample Output

11
  首先有一個很顯然的想法,就是任意一段區間的顏色個數不超過$sqrt(len)$個,否則不如$1$個$1$個直接拼 然後我們只要找如果用$k$種顏色,能從$i$點最遠走到哪 很顯然二分+主席樹就可以解決了 我們設$f[i][j]$表示從$i$往只用$j$種顏色最多往前走到哪 然後討論一下$C_i$上次出現的位置是否被包含即可轉移 程式碼:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5
#define M 40010 6 using namespace std; 7 int n,m,k; 8 int lst[M],a[M],dp[M],f[M][210]; 9 int main() 10 { 11 scanf("%d%d",&n,&m);k=min((int)sqrt(n),m); 12 memset(dp,1,sizeof(dp)),dp[0]=0; 13 scanf("%d",&a[1]);lst[a[1]]=1; 14 f[1][1]=1;f[1][0]=2;dp[1]=1;lst[a[1]]=1;
15 for(int i=2;i<=n;i++) 16 { 17 dp[i]=i,f[i][0]=i+1;scanf("%d",&a[i]); 18 for(int j=1;j<=k;j++) 19 { 20 if(lst[a[i]]>=f[i-1][j]&&f[i-1][j]) 21 f[i][j]=f[i-1][j]; 22 else f[i][j]=f[i-1][j-1]; 23 } 24 for(int j=1;j<=k;j++) 25 if(f[i][j]-1>=0) 26 dp[i]=min(dp[i],dp[f[i][j]-1]+j*j); 27 lst[a[i]]=i; 28 } 29 printf("%d\n",dp[n]); 30 return 0; 31 }