bzoj1584--DP

题目大意:
有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000。现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k。那总的不河蟹度就是所有段的不河蟹度的总和。

思路:
显然如果连续的一段数字相同,我们可以把它们合并成一个数字。

用f[i]表示在1~i这一段的最小不河蟹度。因为答案最大为n,显然不可能出现一段中有超过sqrt(n)个不同的数。

定义b[j],使b[j]+1~i中不同的数的个数等于j且b[j]最小,那么可以得到:f[i]=min{f[j]+j*j},j<=sqrt(n)

怎么求b[j]呢?定义p[k]表示值为k的数前一次出现的位置、c[j]表示b[j]+1~i中有多少个不同的数。

枚举i,更新p,c,对于b[j],若c[j]>j,则需要将b[j]增大,直到a[b[j]]在b[j]+1~i中不出现,一个while即可。

时间复杂度O(n*sqrt(n))

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 char buf[10000000],*p1=buf;
 7 inline void Read(int& x){
 8     char c=*p1++;
 9     for(;c<‘0‘||c>‘9‘;c=*p1++);
10     for(x=0;c>=‘0‘&&c<=‘9‘;x=(x<<3)+(x<<1)+c-48,c=*p1++);
11 }
12 int i,j,k,n,m,x,a[40001],c[40001],f[40001],Last,Pre,p[40001],b[201],Num;
13 bool B[201];
14 int main()
15 {
16     fread(buf,1,10000000,stdin);
17     Read(n);Read(m);
18     for(i=1;i<=n;i++){
19         Read(x);
20         if(x!=a[Num])a[++Num]=x;
21     }
22     n=Num;m=sqrt((double)n);
23     memset(f,127,sizeof(f));
24     for(i=1,f[0]=0;i<=n;i++){
25         for(j=1;j<=m;j++)if(p[a[i]]<=b[j])c[j]++;
26         for(j=1,p[a[i]]=i;j<=m;j++)
27         if(c[j]>j){
28             k=b[j]+1;
29             while(p[a[k]]!=k)k++;
30             b[j]=k;c[j]--;
31         }
32         for(j=1;j<=m;j++)
33         if(f[b[j]]+j*j<f[i])f[i]=f[b[j]]+j*j;
34     }
35     printf("%d",f[n]);
36     return 0;
37 }

bzoj1584

时间: 2024-11-05 15:23:33

bzoj1584--DP的相关文章

bzoj1584 打扫卫生 dp

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1584 题意:找到某种分割序列方法,使得每一段中所含数的种类平方之和最小. 考试时一时脑残连暴力$dp$都没写出来-- 首先暴力dp应该都写得出来--$f[i]=min(f[j]+(cnt[j~i])^2)$ 正解有个比较智障的优化--首先可以想到答案不会差过$n^2$(最差就是每一个一段),因此,我们只需要记录每段中有$1,2,3--sqrt(n)$个不同元素的情况,找到这些段开始的位置的前

[BZOJ1584] [Usaco2009 Mar]Cleaning Up 打扫卫生(DP)

传送门 不会啊,看了好久的题解才看懂 TT 因为可以直接分成n段,所以就得到一个答案n,求解最小的答案,肯定是 <= n 的, 所以每一段中的不同数的个数都必须 <= sqrt(n),不然就不是最小的答案 那么 f[i]表示前i个数的最有解 g[i]表示从当前位置开始,有i个不同的数,最多能往前延伸到哪里 pre[i]表示上一个数为i的位置 cnt[i]表示g[i] + 1 ~ 当前位置 中的不同数的个数 所以 f[i] = min(f[i], f[g[j]] + j * j) 那么问题就是g

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

POJ - 3186 Treats for the Cows (区间DP)

题目链接:http://poj.org/problem?id=3186 题意:给定一组序列,取n次,每次可以取序列最前面的数或最后面的数,第n次出来就乘n,然后求和的最大值. 题解:用dp[i][j]表示i~j区间和的最大值,然后根据这个状态可以从删前和删后转移过来,推出状态转移方程: dp[i][j]=max(dp[i+1][j]+value[i]*k,dp[i][j-1]+value[j]*k) 1 #include <iostream> 2 #include <algorithm&

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st

bzoj1801: [Ahoi2009]chess 中国象棋 [dp]

Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. Input 一行包含两个整数N,M,中间用空格分开. Output 输出所有的方案数,由于值比较大,输出其mod 9999973 Sample Input 1 3 Sample Output 7 HINT 除了在3个格子中都放满炮的的情况外,其它的都可以. 100%的数据中N,M不超过10050%的数据中,N,M至少有一个数不超过

状压DP问题

状态压缩·一 题目传送:#1044 : 状态压缩·一 AC代码: #include <map> #include <set> #include <list> #include <cmath> #include <deque> #include <queue> #include <stack> #include <bitset> #include <cctype> #include <cstdi