[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 }

 

转载于:https://www.cnblogs.com/Slrslr/p/10018846.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值