03 hdu5009
状态转移方程很好想,dp[i] = min(dp[j]+o[j~i]^2,dp[i]) ,o[j~i]表示从j到i颜色的种数。
普通的O(n*n)是会超时的,可以想到o[]最大为sqrt(n),问题是怎么快速找到从i开始往前2种颜色、三种、四种。。。o[]种的位置。
离散化之后,可以边走边记录某个数最后一个出现的位置,初始为-1,而所要求的位置就等于
if(last[a[i]]==-1) 该数没有出现过,num[i][1] = i,num[i][j+1] = num[i-1][j];
else last[a[i]]之前 num[i][1] = i,num[i][j+1] = num[i-1][j],之后num[i][j]= num[i-1][j];
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 #include<map> 11 using namespace std; 12 #define N 50010 13 #define LL long long 14 #define INF 0xfffffff 15 const double eps = 1e-8; 16 const double pi = acos(-1.0); 17 const double inf = ~0u>>2; 18 int a[N]; 19 int dp[N]; 20 int num[2][300],last[N]; 21 map<int,int>f; 22 int main() 23 { 24 int i,j,n; 25 while(scanf("%d",&n)!=EOF) 26 { 27 f.clear(); 28 int g =0 ; 29 for(i = 1; i<= n ;i++) 30 { 31 scanf("%d",&a[i]); 32 if(!f[a[i]]) 33 { 34 f[a[i]] = ++g; 35 a[i] = g; 36 } 37 else a[i] = f[a[i]]; 38 } 39 for(i = 1; i <= n; i++) 40 dp[i] = INF; 41 memset(last,-1,sizeof(last)); 42 memset(num,0,sizeof(num)); 43 int k = sqrt(n*1.0)+1; 44 int tk = 1; 45 dp[1] = 1; 46 last[a[1]] = 1; 47 num[1][1] = 1; 48 dp[0] = 0; 49 for(i = 2; i <= n ;i++) 50 { 51 if(last[a[i]]==-1) 52 { 53 tk+=1; 54 num[i%2][1] = i; 55 for(j = 1; j <= min(tk-1,k-1) ; j++) 56 num[i%2][j+1] = num[(i-1)%2][j]; 57 } 58 else 59 { 60 61 num[i%2][1] = i; 62 for(j = 1; j < min(k,tk) ; j++) 63 { 64 if(last[a[i]]==num[(i-1)%2][j]) break; 65 num[i%2][j+1] = num[(i-1)%2][j]; 66 } 67 for(int g = j+1 ; g <= min(tk,k) ; g++) 68 num[i%2][g] = num[(i-1)%2][g]; 69 } 70 last[a[i]] = i; 71 for(j = 1; j <= min(k,tk); j++) 72 { 73 int po = num[i%2][j+1]; 74 dp[i] = min(dp[i],dp[po]+j*j); 75 // cout<<dp[po]<<" "<<po<<endl; 76 } 77 } 78 printf("%d\n",dp[n]); 79 80 } 81 return 0; 82 }