[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数组的更新

如果 pre[x] > g[x],说明新的数在g[x] + 1 ~ 当前位置 中就包含了,不用更新,

否则g[x]就一直向后删除,直到有一种数全部删除,也就是到pre[x] <= g[x]

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 40001
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, m;
int a[N], pre[N], cnt[N], g[N], f[N];
//f[i]表示前i个的最优解,g[i]表示数量为i最多能向左延伸到哪 

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
	return x * f;
}

int main()
{
	int i, j, k, x;
	n = read();
	m = read();
	m = sqrt(n);
	memset(f, 127, sizeof(f));
	for(i = 1; i <= n; i++) a[i] = read();
	f[0] = 0;
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= m; j++)
			if(pre[a[i]] <= g[j]) cnt[j]++;
		pre[a[i]] = i;
		for(j = 1; j <= m; j++)
			if(cnt[j] > j)
			{
				k = g[j] + 1;
				while(pre[a[k]] > k) k++;
				g[j] = k;
				cnt[j]--;
			}
		for(j = 1; j <= m; j++)
			f[i] = min(f[i], f[g[j]] + j * j);
	}
	printf("%d\n", f[n]);
	return 0;
}

  

时间: 2024-12-14 11:35:35

[BZOJ1584] [Usaco2009 Mar]Cleaning Up 打扫卫生(DP)的相关文章

动态规划 BZOJ1584 [Usaco2009 Mar] Cleaning Up 打扫卫生

1584: [Usaco2009 Mar]Cleaning Up 打扫卫生 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 511  Solved: 349[Submit][Status][Discuss] Description 有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000.现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k.

BZOJ1584 [Usaco2009 Mar]Cleaning Up 打扫卫生

令$f[i]$表示以i为结尾的答案最小值,则$f[i] = min \{f[j] + cnt[j + 1][i]^2\}_{1 \leq j < i}$,其中$cnt[j + 1][i]$表示$[j + 1, i]$内有几个不同的数 对于区间长度为$k$,则答案最大值就是$\sqrt{k}$,所以对于每个$i$我们其实只要枚举$\sqrt{i}$个值就好了 1 /************************************************************** 2 Pr

DP经典 BZOJ 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

BZOJ 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 419  Solved: 278 Description 有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000.现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k.那总的不河蟹度就是所有段的不河蟹度的总和

bzoj 1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

1584: [Usaco2009 Mar]Cleaning Up 打扫卫生 Description 有N头奶牛,每头那牛都有一个标号Pi,1 <= Pi <= M <= N <= 40000.现在Farmer John要把这些奶牛分成若干段,定义每段的不河蟹度为:若这段里有k个不同的数,那不河蟹度为k*k.那总的不河蟹度就是所有段的不河蟹度的总和. Input 第一行:两个整数N,M 第2..N+1行:N个整数代表每个奶牛的编号 Output 一个整数,代表最小不河蟹度 Sampl

【BZOJ】1584: [Usaco2009 Mar]Cleaning Up 打扫卫生

[算法]DP+数学优化 [题意]把n个1~m的数字分成k段,每段的价值为段内不同数字个数的平方,求最小总价值.n,m,ai<=40000 [题解] 参考自:WerKeyTom_FTD 令f[i]表示把前i个数分成若干段的最小价值. 转移中我们定义,从i开始往前到有j个不同的数的最小位置为b[j]. f[i]=f[b[j]-1]+j^2. 考虑最坏情况,每个数自成一段,则总价值为n. 所以当段内不同的数个数>√n时,就不可能是最优解了(此时价值>n). 所以f[i]=f[b[j]-1]+j

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.

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)$个不同元素的情况,找到这些段开始的位置的前

「10.12」木板(数学)&#183;打扫卫生(神仙DP)

A. 木板 一个很简单的数学题,简单推一下就好,路丽姐姐教你学数学. 将式子化出我们发现只需求出$i\times i/n$的个数 那么我们将$n$质因数分解,可知因子个数 为了整除$n$,令$i==\sqrt{n\times k} $,我们需要让$k$含有$n$中奇数个数的因子 然后同时还可以有其他的平方因子,直接爆求即可. 思路积累: 1.对于求$i\times i/n$可以从$n$的因子上下手 B. 打扫卫生 一个$DP$的大神题,考场被各种剪枝cao过 $ \%\%\%\%\%kx,Dua

3400: [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队

3400: [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 129  Solved: 84[Submit][Status][Discuss] Description 农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘 队.他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的