poj 3666 Making the Grade & zoj 3512 Financial Fraud 左偏树 or dp

//poj 3666

//分析:只是在2005年集训队论文黄源河提到的题目上略微有一点点变化

 1 #include"iostream"
 2 #include"cstdio"
 3 using namespace std;
 4 const int maxn = 2100;
 5 int v[maxn],l[maxn],r[maxn],d[maxn];    //节点信息
 6 int N;
 7 int tot,root[maxn],num_now[maxn],num_del[maxn]; //树根信息
 8
 9 __int64 abs(__int64 ans)
10 {
11     return ans<0?-ans:ans;
12 }
13
14 int Merge(int x,int y)
15 {
16     if(!x)  //分治终点
17         return y;
18     if(!y)
19         return x;
20     if(v[x]<v[y])
21         swap(x,y);
22     r[x] = Merge(r[x],y);   //用递归函数进行分治,注意返回值
23     if(d[l[x]]<d[r[x]]) //回溯,维护数组l,r,d
24         swap(l[x],r[x]);
25     d[x] = d[r[x]]+1;
26     return x;   //返回根节点
27 }
28
29 __int64 solve()
30 {
31     int i,j,k;
32     __int64 res = 0;
33     tot = 0;
34     for(i = 1; i<=N; ++i) { //将每个节点都处理成一个区间(左偏树),根节点保存这个区间的中位数信息
35         root[++tot] = i;    //树根信息初始化
36         num_now[tot] = 1;   //树根信息初始化
37         num_del[tot] = 0;   //树根信息初始化
38         l[i] = r[i] = d[i] = 0; //节点信息初始化
39         while(tot>1&&v[root[tot-1]]>v[root[tot]]) { //循环条件为:最后一个区间的中位数小于前一区间;循环槽作为区间合并,并维护树根信息
40             root[tot-1] =  Merge(root[tot-1],root[tot]);    //注意Merge的返回值
41             num_now[tot-1] += num_now[tot];
42             num_del[tot-1] += num_del[tot];
43             --tot;
44             while(num_now[tot]>num_del[tot]+1) {
45                 --num_now[tot];
46                 ++num_del[tot];
47                 root[tot] =  Merge(l[root[tot]],r[root[tot]]);  //注意Merge的返回值
48             }
49         }
50     }
51     for(i = k = 1; i<=tot; ++i) {
52         for(j = 1; j<=num_now[i]+num_del[i]; ++j,++k) {
53             res += abs(v[k]-v[root[i]]);
54         }
55     }
56     return res;
57 }
58
59 int main()
60 {
61     int i;
62     __int64 res_1,res_2;
63     scanf("%d",&N);
64     for(i = 1; i<=N; ++i) {
65         scanf("%d",&v[i]);
66     }
67     res_1 = solve();
68     for(i = 1; i<=N; ++i) {
69         v[i] *= -1;
70     }
71     res_2 = solve();
72     printf("%I64d\n",res_1<res_2?res_1:res_2);
73     return 0;
74 }

//zoj 3512

//感觉poj 3666数据太弱就去zoj 找了一道看起来一样的题目去交了,不能用__int64 ce一发,没读题wa一发,没注意数据范围re一发,不能交%I64d又wa一发,第五发才ac......

 1 #include"iostream"
 2 #include"cstdio"
 3 using namespace std;
 4 const int maxn = 50100;
 5 int v[maxn],l[maxn],r[maxn],d[maxn];    //节点信息
 6 int N;
 7 int tot,root[maxn],num_now[maxn],num_del[maxn]; //树根信息
 8
 9 long long abs(long long ans)
10 {
11     return ans<0?-ans:ans;
12 }
13
14 int Merge(int x,int y)
15 {
16     if(!x)  //分治终点
17         return y;
18     if(!y)
19         return x;
20     if(v[x]<v[y])
21         swap(x,y);
22     r[x] = Merge(r[x],y);   //用递归函数进行分治,注意返回值
23     if(d[l[x]]<d[r[x]]) //回溯,维护数组l,r,d
24         swap(l[x],r[x]);
25     d[x] = d[r[x]]+1;
26     return x;   //返回根节点
27 }
28
29 long long solve()
30 {
31     int i,j,k;
32     long long res = 0;
33     tot = 0;
34     for(i = 1; i<=N; ++i) { //将每个节点都处理成一个区间(左偏树),根节点保存这个区间的中位数信息
35         root[++tot] = i;    //树根信息初始化
36         num_now[tot] = 1;   //树根信息初始化
37         num_del[tot] = 0;   //树根信息初始化
38         l[i] = r[i] = d[i] = 0; //节点信息初始化
39         while(tot>1&&v[root[tot-1]]>v[root[tot]]) { //循环条件为:最后一个区间的中位数小于前一区间;循环槽作为区间合并,并维护树根信息
40             root[tot-1] =  Merge(root[tot-1],root[tot]);    //注意Merge的返回值
41             num_now[tot-1] += num_now[tot];
42             num_del[tot-1] += num_del[tot];
43             --tot;
44             while(num_now[tot]>num_del[tot]+1) {
45                 --num_now[tot];
46                 ++num_del[tot];
47                 root[tot] =  Merge(l[root[tot]],r[root[tot]]);  //注意Merge的返回值
48             }
49         }
50     }
51     for(i = k = 1; i<=tot; ++i) {
52         for(j = 1; j<=num_now[i]+num_del[i]; ++j,++k) {
53             res += abs(v[k]-v[root[i]]);
54         }
55     }
56     return res;
57 }
58
59 int main()
60 {
61     int i;
62     long long res_1;
63     while(scanf("%d",&N)&&N) {
64         for(i = 1; i<=N; ++i) {
65             scanf("%d",&v[i]);
66         }
67         res_1 = solve();
68         printf("%lld\n",res_1);
69     }
70     return 0;
71 }

//看了看别人的blog发现这题还能dp搞,先挖个坑随后再填...

时间: 2024-11-06 10:51:10

poj 3666 Making the Grade & zoj 3512 Financial Fraud 左偏树 or dp的相关文章

ZOJ 3512 Financial Fraud (左偏树)

题意:给定一个序列,求另一个不递减序列,使得Abs(bi - ai) 和最小. 析:首先是在每个相同的区间中,中位数是最优的,然后由于要合并,和维护中位数,所以我们选用左偏树来维护,当然也可以用划分树来做. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #inclu

poj 3016 K-Monotonic 左偏树 + 贪心 + dp

//poj 3016 K-Monotonic//分析:与2005年集训队论文黄源河提到的题目类似,给定序列a,求一序列b,b不减,且sigma(abs(ai-bi))最小.//思路:去除左偏树(大根堆)一半的节点(向上取整),让左偏树的根节点上存放中位数:每个左偏树的根节点表示一个等值区间//在本题中,我们将一段区间 与 一颗左偏树等同:将求调整给定数列 vi 为不减序列的代价 与 求取数列 bi 等同 1 #include"iostream" 2 #include"cstd

POJ3666-Making the Grade(左偏树 or DP)

左偏树 炒鸡棒的论文<左偏树的特点及其应用> 虽然题目要求比论文多了一个条件,但是……只需要求非递减就可以AC……数据好弱…… 虽然还没想明白为什么,但是应该觉得应该是这样——求非递减用大顶堆,非递增小顶堆…… 这题和bzoj1367题意差不多,但是那题求的是严格递增.(bzoj找不到那道题,可能是VIP或什么原因? 严格递增的方法就是每一个数字a[i]都要减去i,这样求得的b[i]也要再加i,保证了严格递增(为什么对我就不知道了 代码比较水,因为题目数据的问题,我的代码也就钻了空子,反正ac

zoj 2334 Monkey King/左偏树+并查集

原题链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1389 大致题意:N只相互不认识的猴子(每只猴子有一个战斗力值) 两只不认识的猴子之间发生冲突,两只猴子会分别请出它们认识的最强壮的 猴子进行决斗.决斗之后这,两群猴子都相互认识了. 决斗的那两只猴子战斗力减半...有m组询问 输入a b表示猴子a和b发生了冲突,若a,b属于同一个集合输出-1 否则输出决斗之后这群猴子(已合并)中最强的战斗力值... 具体思路:用并查

POJ 3666 Making the Grade [DP]

题意: 给定一个序列,以最小代价将其变成单调不增或单调不减序列,这里的代价看题目公式. 思路: 很容易想到是DP. 1. 对前i个序列,构成的最优解其实就是与两个参数有关.一个是这个序列处理后的最大值mx,和这个序列处理的代价值cost. 显然最大值mx最小最好(这样第i+1个值可以不花代价直接接在其后面的可能性更大),cost最小也最好(题意要求),但是两者往往是鱼和熊掌. 用dp[i][j]表示:前i个数构成的序列,这个序列最大值为j,dp[i][j]的值代表相应的cost. 所以状态转移方

[2016-03-28][POJ][3666][]Making the Grade]

时间:2016-03-28 17:23:08 星期一 题目编号:[2016-03-28][POJ][3666][]Making the Grade] 分析:dp[i][j]表示把改到第i个数,且把a[i]改成b[i]需要的最少代价,已知b[j]递增,dp[i][j]由dp[i - 1][k]递推过来,如果改成非增,那么就要求 a[j] <= a[k],所以dp[i][j] = min(dp[i - 1][k] + d) k < j; #include <algorithm> #in

Poj 3666 Making the Grade (排序+dp)

题目链接: Poj 3666 Making the Grade 题目描述: 给出一组数,每个数代表当前位置的地面高度,问把路径修成非递增或者非递减,需要花费的最小代价? 解题思路: 对于修好的路径的每个位置的高度肯定都是以前存在的高度,修好路后不会出现以前没有出现过得高度 dp[i][j]代表位置i的地面高度为第j个高度,然后我们可以把以前的路修好后变成非递减路径,或者把以前的路径首尾颠倒,然后修成非递减路径.状态转移方程为:dp[i][j] = min(dp[i-1][k]) + a[i] -

POJ 3666 Making the Grade(数列变成非降序/非升序数组的最小代价,dp)

传送门: http://poj.org/problem?id=3666 Making the Grade Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9468   Accepted: 4406 Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would lik

POJ - 3666 Making the Grade(dp+离散化)

Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ