[usaco jan 09] 气象牛 baric [dp]

题面:

传送门

思路:

题意有点绕,实际上就是给你一个计算规则,让你取最少的元素,通过这个计算方式,得到一个小于指定误差上限的结果

这个规则分为三个部分,这里分别用pre,sum,suf表示

因为给定的元素个数(天数)很少,可以使用O(n^3)算法,因此考虑使用经过了预处理的dp解决问题

具体地,设dp[i][j]表示前i个元素使用了j个且一定取用了第i个时可能达到的最小误差值

预处理:pre[i]表示通过第一种计算方式得到的,第一个元素取第i个时得到的误差

suf[i]同理,为第三种计算方式

sum[i][j]则表示取了i和j且不取中间的元素时,中间的元素产生的误差

这样dp[i][1]=pre[i],dp[i][j]=dp[k][j-1]+sum[k][i](k=1...i-1),然后用dp[i][j]+suf[j]更新答案即可

Code:

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #define inf 0x7fffffff/2
 7 using namespace std;
 8 int n,m,a[110];
 9 int dp[110][110];
10 //dp[i][j]: prefix 1-i,chosen j
11 int pre[110],suf[110],sum[110][110];
12 int abs(int k){
13     if(k>=0) return k;
14     else return -k;
15 }
16 int main(){
17     freopen("baric.in","r",stdin);
18     freopen("baric.out","w",stdout);
19     int i,j,k,tmp1,tmp2,t,l;
20     scanf("%d%d",&n,&m);
21     int ans=m,anss=n;
22     for(i=1;i<=n;i++){
23         scanf("%d",&a[i]);
24         dp[i][1]=0;
25     }
26     for(i=1;i<=n-2;i++){
27         for(j=i+2;j<=n;j++){
28             for(k=i+1;k<j;k++){
29                 sum[i][j]+=abs((a[k]<<1)-a[i]-a[j]);
30             }
31         }
32     }
33     for(i=1;i<=n;i++){
34         for(j=1;j<i;j++) pre[i]+=abs(a[i]-a[j])<<1;
35         dp[i][1]=pre[i];
36         for(j=n;j>i;j--) suf[i]+=abs(a[i]-a[j])<<1;
37     }
38     for(i=2;i<=n;i++){
39         for(j=2;j<=i;j++){
40             dp[i][j]=inf/2;
41             for(k=1;k<i;k++) dp[i][j]=min(dp[i][j],dp[k][j-1]+sum[k][i]);
42             if(dp[i][j]+suf[i]<m){
43                 if(j<ans) ans=j,anss=dp[i][j]+suf[i];
44                 else if(j==ans&&dp[i][j]+suf[i]<anss) anss=dp[i][j]+suf[i];
45             }
46         }
47     }
48     printf("%d %d",ans,anss);
49 } 

原文地址:https://www.cnblogs.com/dedicatus545/p/8457084.html

时间: 2024-10-11 17:28:31

[usaco jan 09] 气象牛 baric [dp]的相关文章

[BZOJ1575] [Usaco2009 Jan]气象牛Baric(DP)

传送门 DP f[i][j]表示前i个中选j个的最优解 预处理g[i][j]表示选i~j对答案的贡献 那么就可以n^3乱搞了! 注意边界 #include <cstdio> #include <cstring> #include <iostream> #define N 110 #define abs(x) ((x) < 0 ? -(x) : (x)) #define min(x, y) ((x) < (y) ? (x) : (y)) int n, e, a

bzoj 1575: [Usaco2009 Jan]气象牛Baric

Description 为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1...M_N(1 <= M_i <= 1,000,000). Betsy想找出一部分测量结果来总结整天的气压分布. 她想用K(1 <= K <= N)个数s_j (1 <= s_1 < s_2 < ... < s_K <= N)来概括所有测量结果. 她想限制如下的误差: 对于任何测量结果子集,每一个非此

【动态规划】bzoj1575: [Usaco2009 Jan]气象牛Baric

预处理普通动态规划:庆祝1A三连 Description 为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1...M_N(1 <= M_i <= 1,000,000). Betsy想找出一部分测量结果来总结整天的气压分布. 她想用K(1 <= K <= N)个数s_j (1 <= s_1 < s_2 < ... < s_K <= N)来概括所有测量结果. 她想限制如下的误差:

[usaco jan 09] 安全路径 travel [最短路径树]

题面: 传送门 思路: 既然最后一条边不能走,那么就一定是换了一条路,一条不经过这最后一条边的路 如果想要这条路最短,那么其在路上一定尽可能多地走了最短路径 因此,我们对这张图跑一遍从1开始的单源最短路,并建立出最短路径树 那么新的路径(1->u)一定是这样构成的:(1->v)+edge(v,w)+(w->u),其中w是u在最短路径树上的后代 那么,我们对于每一条非树边(u,v),其树上路径上所有点(除了lca)的答案,都可以被dis[u]+dis[v]+w(u,v)-dis[路径上的点

USACO JAN 2012 Bronze

Problem 1: Gifts [Kalki Seksaria and Brian Dean, 2012] Farmer John wants to give gifts to his N (1 <= N <= 1000) cows, using his total budget of B (1 <= B <= 1,000,000,000) units of money. Cow i requests a gift with a price of P(i) units, and

[BZOJ1679][Usaco2005 Jan]Moo Volume 牛的呼声

1679: [Usaco2005 Jan]Moo Volume 牛的呼声 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 1097  Solved: 571 [Submit][Status][Discuss] Description Farmer John has received a noise complaint from his neighbor, Farmer Bob, stating that his cows are making too

cogs 181. [USACO Jan07] 最高的牛

181. [USACO Jan07] 最高的牛 ★★   输入文件:tallest.in   输出文件:tallest.out   简单对比时间限制:1 s   内存限制:32 MB FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are told

[USACO 2012 Jan Silver] Bale Share【DP】

传送门:http://www.usaco.org/index.php?page=viewproblem2&cpid=107 没想到太不应该了,真的不应该啊! f[i][j][k]表示前i个包,第一个包里共有j大小的物品,第二个包里共有k大小的物品是否成立,则方程为: f[i][j][k] = f[i - 1][j - a[i]][k] || f[i - 1][j][k - a[i]] || f[i - 1][j][k]; 观察方程,可以省去数组a改用单独一个变量,并使用滚动数组,详见代码. #i

Jan 09 - House Robber; DP;

用DP思维很好解决 注意终止条件 这里添加了一个数组 length = nums.length + 1; 代码: public class Solution { public int rob(int[] nums) { int[] money = new int[nums.length+1]; if(nums.length == 0) return 0; for(int i = 0; i <= nums.length; i++){ if(i == 0) money[i] = 0; else if