bzoj1584 9.20考试 cleaning up 打扫卫生
1584: [Usaco2009 Mar]Cleaning Up 打扫卫生
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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比较。
1 #pragma GCC optimze("O3") 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cstring> 6 #include<queue> 7 #include<algorithm> 8 #include<cmath> 9 #include<map> 10 #include<vector> 11 #define N 40005 12 using namespace std; 13 int n,m,a[N],f[N],pre[N]; 14 bool fw[N]; 15 int main() 16 { 17 scanf("%d%d",&n,&m); 18 for(int i=1;i<=n;i++) 19 scanf("%d",&a[i]); 20 memset(f,0xf,sizeof(f)); 21 f[0]=0; 22 memset(pre,-1,sizeof(pre)); 23 for(int i=1;i<=n;i++) 24 { 25 f[i]=i; 26 int js=0; 27 memset(fw,0,sizeof(fw)); 28 for(int j=i;j>=0;j--) 29 { 30 if(!fw[a[j]])js++,fw[a[j]]=1; 31 if(js*js>=i)break; 32 if(f[i]>f[j-1]+js*js) 33 f[i]=f[j-1]+js*js; 34 } 35 pre[a[i]]=i; 36 } 37 printf("%d\n",f[n]); 38 return 0; 39 }