USACO泛做

打扫卫生

题意:一段序列,分为若干段,每段分值为该段中不同数字个数平方,求划分方案使分值和最小。

分析:n^2DP很好写 f[i]:=min(f[j]+cost[i+1,j]); 考虑优化,由于任何序列其最小分值和最大为n(每个元素自成一段),故可推出最优方案中,每段分值不可能超过n,也就是不同元素个数不超过根号n,故方程改为f[i]:=min(f[b[j]]+j*j); j<=√n; b[j]表示一个位置编号,意思是从i开始到b[j]+1,共有j个不同的数字,然后维护即可。

program cleanup;
var
  f,a,b,c,hash:array[0..100000]of int64;
  n,m,t:int64; i,j:longint;
function min(x,y:longint):longint;
begin
  if x<y then min:=x else min:=y;
end;
begin
  readln(n,m);
  for i:=0 to m do hash[i]:=0;
  for i:=1 to n do read(a[i]);
  m:=trunc(sqrt(n)); f[0]:=0;
  for i:=1 to n do
   begin
     f[i]:=maxlongint;
     for j:=1 to m do
      if hash[a[i]]<=b[j] then inc(c[j]);
     hash[a[i]]:=i;
     for j:=1 to m do
      if c[j]>j then
       begin
         t:=b[j]+1;
         while hash[a[t]]>t do inc(t);
         b[j]:=t; dec(c[j]);
       end;
     for j:=1 to m do
      f[i]:=min(f[i],f[b[j]]+j*j);
   end;
  writeln(f[n]);
end.

时间: 2024-10-11 11:42:33

USACO泛做的相关文章

历年NOIP水题泛做

快noip了就乱做一下历年的noip题目咯.. noip2014 飞扬的小鸟 其实这道题并不是很难,但是就有点难搞 听说男神错了一个小时.. 就是$f_{i,j}$表示在第$i$个位置高度为$j$的时候最小点击次数 递推的话对于上升的情况只做一次,后面几次在后面再做.. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace st

codeforce 泛做

1A - Theatre Square 题意:有一个规模为n*m的剧院,用a*a的地板来铺满,问需要多少块木板. 思路:水题. 1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cstdio> 7 #include<vector> 8 #define

# 清北冬令营真题泛做

清北冬令营真题泛做 前言 这段时间为了准备冬令营把清北冬令营真题都做了一下.更个博回顾一下(免得你们老说我咕咕咕). 先写良心PKU的题再写THU的题, 主要是THU的题和PKU比起来真的毒瘤好多...... PKUWC2018 [PKUWC2018]Minimax 一个比较显然的暴力是归并排序,每次直接前后缀计算答案即可. 为啥不用线段树合并代替归并排序呢? 暴力线段树合并,合并的过程中顺便算一下即可,由于权值区间不交所以复杂度一个\(log\). [PKUWC2018]Slay the Sp

HAOI2015 泛做

T1 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益.问受益最大值是多少.N,K<=2000 这个树形dp不是很好想...因为贡献十分混乱... 题解十分神奇...我们记f[i][j]为i的子树有j个黑点的最大权值. 注意直接dp十分蛋疼,这个权值指的是,这个子树内部的贡献,以及i与父亲之间的边对答案的贡献(比如这条边对黑点对距离和的贡

Shoi2017试题泛做

一口气做完六个省的省选(误) Day1 [Shoi2017]期末考试 枚举最大的天数,然后代价贪心地O(1)计算. 1 #include <cstdio> 2 #include <algorithm> 3 4 #define R register 5 typedef long long ll; 6 #define maxn 100010 7 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) 8 #define cmin(_a,

[DynamicProgramming]动态规划题目泛做

Educational Codeforces Round 12 F 大意: 求n(n<=1011)以内恰好有4个因数的数的个数 分析: 首先一个数恰好有4个因数,说明它质因数分解之后是两个质数的乘积或是一个质数的三次方,对于后一种情况我们直接n1/3就能算出来,关键在于计算n以内有多少个数是两个素数的乘积. 设n=p1?p2,则必然有p1<n?√,p2>n?√,我们枚举p1,那么问题就在于np1 内有多少个素数. 这一点我们用dp来解决. 记pj为第j个素数,dp[n][j]为[1,n]

Hnoi2017试题泛做

Day1 4825: [Hnoi2017]单旋 注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序. 所以我们可以离线地把这棵树的中序遍历求出来.然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态. 接着我们发现将最大.最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1.于是我们就只要支持单点修改.区间加.单点查询的数据结构即可.树状数组就好了. 然后树的形态维护的时候大力判断一下就好啦. 1 #include <cstdio> 2

Cqoi2017试题泛做

Day1 4813: [Cqoi2017]小Q的棋盘 树形背包DP. 1 #include <cstdio> 2 3 #define maxn 110 4 #define R register 5 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) 6 struct Edge { 7 Edge *next; 8 int to; 9 } *last[maxn], e[maxn << 1], *ecnt = e; 10 inline

背包DP泛做

DP太弱了,要多做. 结果做了一堆傻逼题... 洛谷P2639: 01背包 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define max(a, b) (a < b ? b : a) const int MAXN = 500; using namespace std; inline int read() { int x = 0, w = 1; c