1584: [Usaco2009 Mar]Cleaning Up 打扫卫生
Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 549 Solved: 382
[Submit][Status][Discuss]
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
1
2
1
3
2
2
3
4
3
4
3
1
4
Sample Output
11
HINT
这道题当时是被m坑了所以先提前声明一下m没有任何卵用,没有任何卵用,没有任何卵用!又被丝薄出题人坑了。
当时以为m是限制的次数,然后就开始手推了十多分钟的样例,各种搞都没用,然后就快崩溃了,TMm到底是什么呀?于是万念俱灰的我打了一个大爆搜,然后惊喜的发现m真的不是次数,然后就等着这个暴力拿分了,连正解都忘了去想,天知道O(n^2)能拿70分,直接跪了,疼啊。
正解个人表示根本看不懂,于是乎向指针恒学了一下暴力。
同n^2的暴力一样,原理也是一样,暴力枚举,但我们可以观察到对于一个点,他的最优解一定小于等于i所以我们只要枚举到不同的点有sqrt(i)就可以直接退出了,省了不少时间,其次也是最重要的一点,别用min,用if比较。
#pragma GCC optimze("O3")
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#define N 40005
using namespace std;
int n,m,a[N],f[N],pre[N];
bool fw[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
memset(f,0xf,sizeof(f));
f[]=;
memset(pre,-,sizeof(pre));
for(int i=;i<=n;i++)
{
f[i]=i;
int js=;
memset(fw,,sizeof(fw));
for(int j=i;j>=;j--)
{
if(!fw[a[j]])js++,fw[a[j]]=;
if(js*js>=i)break;
if(f[i]>f[j-]+js*js)
f[i]=f[j-]+js*js;
}
pre[a[i]]=i;
}
printf("%d\n",f[n]);
return ;
}