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     Problem: 1584
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:112 ms
 7     Memory:1120 kb
 8 ****************************************************************/
 9
10 #include <cstdio>
11 #include <algorithm>
12
13 using namespace std;
14 const int N = 4e4 + 5;
15 const int MXlen = 250;
16
17 int n, m;
18 int a[N], f[N], seq[MXlen], now[MXlen];
19 int st, mxlen, nowlen;
20
21 inline int read();
22
23 inline int sqr(int x) {
24     return x * x;
25 }
26
27 int main() {
28     int i, j;
29     n = read(), m = read();
30     for (i = 1; i <= n; ++i) a[i] = read();
31     for (mxlen = 1; mxlen * mxlen <= n; ++mxlen);
32     --mxlen;
33     for (i = 1; i <= n; ++i) {
34         f[i] = i;
35         for (st = 0, j = 1; j <= nowlen; ++j)
36             if (seq[j] == a[i]) {
37                 st = j;
38                 break;
39             }
40         if (!st) {
41             if (nowlen != mxlen) {
42                 seq[++nowlen] = a[i];
43                 now[nowlen] = i;
44             } else {
45                 for (j = 1; j < nowlen; ++j)
46                     seq[j] = seq[j + 1], now[j] = now[j + 1];
47                 seq[nowlen] = a[i], now[nowlen] = i;
48             }
49         } else {
50             for (j = st; j < nowlen; ++j)
51                 seq[j] = seq[j + 1], now[j] = now[j + 1];
52             seq[nowlen] = a[i], now[nowlen] = i;
53         }
54         for (j = nowlen; j >= 2; --j)
55             f[i] = min(f[i], f[now[j - 1]] + sqr(nowlen - j + 1));
56     }
57     printf("%d\n", f[n]);
58     return 0;
59 }
60
61 inline int read() {
62     static int x;
63     static char ch;
64     x = 0, ch = getchar();
65     while (ch < ‘0‘ || ‘9‘ < ch)
66         ch = getchar();
67     while (‘0‘ <= ch && ch <= ‘9‘) {
68         x = x * 10 + ch - ‘0‘;
69         ch = getchar();
70     }
71     return x;
72 }

时间: 2024-10-15 11:59:25

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

动态规划 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 打扫卫生(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

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

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 打扫卫生

[算法]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.

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只奶牛来参加他的

bzoj3401[Usaco2009 Mar]Look Up 仰望*

bzoj3401[Usaco2009 Mar]Look Up 仰望 题意: 约翰的N头奶牛站成一排,奶牛i的身高是Hi.对于奶牛i,如果奶牛j满足i<j且Hi<Hj,我们可以说奶牛i可以仰望奶牛j.求出每只奶牛离她最近的仰望对象.n≤100000. 题解: 用一个单调栈维护即可. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) f

1583: [Usaco2009 Mar]Moon Mooing 哞哞叫

1583: [Usaco2009 Mar]Moon Mooing 哞哞叫 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 244  Solved: 126[Submit][Status][Discuss] Description Input 第一行两个数,C和N 第二行3个数,a1,b1,c1 第三行3个数,a2,b2,c2 Output 一个整数代表最长的那一次嚎叫 Sample Input 3 10 4 3 3 17 8 2 Sample Out