http://acm.hdu.edu.cn/showproblem.php?pid=5009

2014网络赛 西安 比较难的题

Paint Pearls

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1951    Accepted Submission(s): 631

Problem Description
Lee has a string of n pearls. In the beginning, all the pearls have
no color. He plans to color the pearls to make it more fascinating. He
drew his ideal pattern of the string on a paper and asks for your help.

In each operation, he selects some continuous pearls and all these pearls will be painted to their target colors. When he paints a string which has k different target colors, Lee will cost k2 points.

Now, Lee wants to cost as few as possible to get his ideal string. You should tell him the minimal cost.

 
Input
There are multiple test cases. Please process till EOF.

For each test case, the first line contains an integer n(1 ≤ n ≤ 5×104), indicating the number of pearls. The second line contains a1,a2,...,an (1 ≤ ai ≤ 109) indicating the target color of each pearl.

 
Output
For each test case, output the minimal cost in a line.
 
Sample Input
3
1 3 3
10
3 4 2 4 4 2 4 3 2 2
 
Sample Output
2
7
 
Source
 
Recommend
hujie   |   We have carefully selected several similar problems for you:  5041 5040 5039 5038 5036

题意:

给出n个数,代表一排珍珠要涂的颜色,刚开始全都没有颜色。可以对连续若干个珍珠发动连涂,代价是这若干珍珠的不同颜色数的平方。涂完这串珍珠,求最小代价和。

题解:

O(n*根号n)的DP,还需要一些超碉方法来处理。

先进行一些小处理,最多5W珍珠,颜色其实也最多5W种,它给的颜色有10^9种,我先用map处理一下变成5w种。

然后连续若干个相同颜色的其实可以合并成一个。经过上面这两个处理,得到了新的珍珠数组。然后才是难点。

先看,最多5W个珍珠,233^2>50000,也就是233连涂就已经超过5W个分别单独涂的代价了。

动态规划,dp[i]表示涂完第i个珍珠所需的代价。

dp[i] = max( dp[i] , dp[k] + j*j)

j为j之后一直到i的不同颜色数。不同颜色数 j 最多为根号n,所以DP是O(n*根号n)的。

i从1到n,j从1到j*j>=i(因为1~i分别单独涂的代价是i)。

关键是如何求每个j对应的k。

假设已知对 i 的每个 j 对应的k,则我们可以求出对 i+1 的每个 j 对应的 k。比较容易想到。具体是这样:

设i的j对应的k为k(i,j)。

b[]为珍珠数组,

若b[i+1]为新出现的颜色,则

  k( i+1 , j+1 ) = k( i , j )

  k( i+1 , 1 ) = i + 1

若b[i+1]为以前就有的颜色,我们用一个last[]数组存每个颜色最后出现的位置,则

对 ( k( i , j ) > last[ b[i+1] ] ) 的j 有 k( i+1 , j+1 ) = k( i , j )

对 ( k( i , j ) < last[ b[i+1] ] ) 的j 则没有变化。

k( i+1 , 1 ) = i + 1

这样我们就能从i 推到 i+1了。

可以发现其中的操作都是连续一堆数向后移动一个下标,如果数组直接搞会TLE。我是用了模拟链表来搞,新颜色出现就直接在后面加,出现旧颜色就把那个分界点删掉,然后在后面加。

代码:

 //#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
using namespace std;
#define ll long long
#define usll unsigned ll
#define mz(array) memset(array, 0, sizeof(array))
#define minf(array) memset(array, 0x3f, sizeof(array))
#define REP(i,n) for(i=0;i<(n);i++)
#define FOR(i,x,n) for(i=(x);i<=(n);i++)
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define WN(x) printf("%d\n",x);
#define RE freopen("xorin.txt","r",stdin)
#define WE freopen("xorin.txt","w",stdout)
#define mp make_pair
#define pb push_back
const int maxn=;
const int maxm=;
int b[maxn],bn;
int cc[maxm+];
int dp[maxn];
int d[maxn],dn,dq;///d[j]存着某个位置,存了dn个在1~dn,最后一个在dq;
int L[maxn],R[maxn];///L[d[dn]]存着第二个不同的的d[]的下标,再L一下是第三个的
int last[maxn];///last[x]表示x上次出现的位置的d[]的下标
int farm() {
int i,j,k;
// FOR(j,1,bn)printf("%3d",b[j]);
// puts("");
mz(last);
L[]=-;
d[]=;
b[]=;
dn=;
dq=;
d[]=;
L[]=;
R[]=;
last[b[]]=;
FOR(i,,bn) {
dp[i]=i;
j=;
for(k=L[dq]; k!=-; k=L[k]) {
if(cc[j]>=dp[i])break;
//printf("dp[%d]=min(%d , %d + %d)\n",i,dp[i], dp[d[k]],cc[j]);
dp[i]=min(dp[i] , dp[d[k]] + cc[j]);
j++;
}
if(last[b[i+]]==) {
dn++;
R[dq]=dn;
L[dn]=dq;
R[dn]=;
dq=dn;
d[dn]=i+; } else {
j=last[b[i+]];
L[R[j]]=L[j];
R[L[j]]=R[j];
L[j]=dq;
R[j]=;
R[dq]=j;
dq=j;
d[dq]=i+;
}
last[b[i+]]=dq;
}
return dp[bn];
} int a[maxn];
map<int,int>S;
int main() {
int n,i,t;
int x;
FOR(i,,maxm) {
cc[i]=i*i;
} while(RD(n)!=EOF) {
S.clear();
int cnt=;
bn=;
FOR(i,,n) {
RD(x);
int t=S[x];
if(t==) S[x]=t=++cnt;
if(b[bn]!=t) b[++bn]=t;
}
printf("%d\n",farm());
}
return ;
}

有点难,比赛时看了半天不懂,比完了搞了半天也不太懂……搞出来了以后发现思路应该还是挺简单的……

网上找到很多不同的方法,kuangbin菊苣说这个很水,他的并查集的方法我看不太懂……

hdu5009 Paint Pearls (DP+模拟链表)的更多相关文章

  1. hdu-5009 Paint Pearls DP+双向链表 with Map实现去重优化

    http://acm.hdu.edu.cn/showproblem.php?pid=5009 题目要求对空序列染成目标颜色序列,对一段序列染色的成本是不同颜色数的平方. 这题我们显然会首先想到用DP去 ...

  2. hdu5009 Paint Pearls[指针优化dp]

    Paint Pearls Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  3. HDU - 5009 Paint Pearls(dp+优化双向链表)

    Problem Description Lee has a string of n pearls. In the beginning, all the pearls have no color. He ...

  4. HDU-5009 Paint Pearls 动态规划 双向链表

    题目链接:https://cn.vjudge.net/problem/HDU-5009 题意 给一串序列,可以任意分割多次序列,每次分割的代价是被分割区间中的数字种数. 求分割区间的最小代价.n< ...

  5. HDU 5009 Paint Pearls 双向链表优化DP

    Paint Pearls Problem Description   Lee has a string of n pearls. In the beginning, all the pearls ha ...

  6. HDU 5009 Paint Pearls(西安网络赛C题) dp+离散化+优化

    转自:http://blog.csdn.net/accelerator_/article/details/39271751 吐血ac... 11668627 2014-09-16 22:15:24 A ...

  7. HDU 5009 Paint Pearls (动态规划)

    Paint Pearls Problem Description Lee has a string of n pearls. In the beginning, all the pearls have ...

  8. Paint Pearls

    Paint Pearls 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5009 dp+双向链表优化 看到题目,很自然地可以定义状态:dp[i]表示涂好 ...

  9. AC日记——Paint Pearls hdu 5009

    Paint Pearls 思路: 离散化+dp+剪枝: dp是个n方的做法: 重要就在剪枝: 如果一个长度为n的区间,有大于根号n种颜色,还不如一个一个涂: 来,上代码: #include <c ...

随机推荐

  1. Leetcode 131. Palindrome Partitioning

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  2. hdu5183 hash大法

    维护前缀和sum[i]=a[0]-a[1]+a[2]-a[3]+…+(-1)^i*a[i]枚举结尾i,然后在hash表中查询是否存在sum[i]-K的值.如果当前i为奇数,则将sum[i]插入到has ...

  3. dedecms /member/uploads_edit.php SQL Injection Vul

    catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 Dedecms 5.3版本下的member/uploads_edit.p ...

  4. 数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作

    一.简述 ...由于链表在空间的合理利用上和插入.删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点:另一 ...

  5. 看看你的正则行不行——正则优化一般的json字符串

    json字符串很有用,有时候一些后台接口返回的信息是字符串格式的,可读性很差,这个时候要是有个可以格式化并高亮显示json串的方法那就好多了,下面看看一个正则表达式完成的json字符串的格式化与高亮显 ...

  6. InternalsVisibleToAttribute——把internal成员暴露给指定的友元程序集

    友元程序集简介 我们知道一个类中被定义为internal的成员(包括类型.方法.属性.变量.事件)是只能在同一个程序集中被访问到的(当然了,我这里说的是正常的方式,不包括通过反射来访问).这个规则在. ...

  7. C#和Javascript的try…catch…finally的一点差别

    C#中规定:如果程序的控制流进入了一个带finally块的try语句,那么finally语句块始终会被执行 例子: class Program { static void Main(string[] ...

  8. Oracle 数据库对象

    数据库对象是数据库的组成部分,常常用CREATE命令进行创建,可以使用ALTER命令修改,用DROP执行删除操作.前面已经接触过的数据库对象有表.用户等. 今天将学习更多的Oracle数据库对象: 同 ...

  9. POJ 1365 Prime Land(数论)

    题目链接: 传送门 Prime Land Time Limit: 1000MS     Memory Limit: 10000K Description Everybody in the Prime ...

  10. primefaces p:dataExporter filename 支持中文 utf8

    p:fileDownload and p:dataExporter : for p:fileDownload, the Content-Disposition header should be set ...