【以前的空间】Poj 3071 Cut the Sequence

dp+单调性+平衡树

在看某篇论文中看到这道题,但是那篇论文不如这个http://www.cnblogs.com/staginner/archive/2012/04/02/2429850.html 大神的空间写的好(还是说我太弱需要详解……)。

其实要说的在大神的博客里面已经说的很好……

比如f[i],然后j表示满足a[j+1]+a[j+2]+……+a[i]<=m的最小值。然后我们假定a[j]--a[i]中最大数的下标为k,那么就有j+1<=l<=k时,f[j+1]+a[k]<=f[j+2]+a[k]<=f[j+3]+a[k]……<=f[k-1]+a[k],也就是只要在把在k前或者k到i的区间分为一个区间,那么这个区间的最大值就是a[k]。这样f数组就是递增的。

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
var
  left,right,s,q,d:array[0..501000]of longint;
  key,a,sum,f:array[0..500100]of int64;
  i,j,k,l,n,tot,t,head,tail,deci:longint;
  m:int64;

procedure rightrotate(var t:longint);
var
  k:longint;
begin
  k:=left[t];
  left[t]:=right[k];
  right[k]:=t;
  s[k]:=s[t];
  s[t]:=s[left[t]]+s[right[t]]+1;
  t:=k;
end;

procedure leftrotate(Var t:longint);
var
  k:longint;
begin
  k:=right[t];
  right[t]:=left[k];
  left[k]:=t;
  s[k]:=s[t];
  s[t]:=s[left[t]]+s[right[t]]+1;
  t:=k;
end;

procedure maintain(var t:longint);
begin
  if s[left[left[t]]]>s[right[t]] then begin
    rightrotate(t);
    maintain(right[t]);
    maintain(t);
  end;
  if s[right[left[t]]]>s[right[t]] then begin
    leftrotate(left[t]);
    rightrotate(t);
    maintain(left[t]);
    maintain(right[t]);
    maintain(t);
  end;
  if s[right[right[t]]]>s[left[t]] then begin
    leftrotate(t);
    maintain(left[t]);
    maintain(t);
  end;
  if s[left[right[t]]]>s[left[t]] then begin
    rightrotate(right[t]);
    leftrotate(t);
    maintain(left[t]);
    maintain(right[t]);
    maintain(t);
  end;
end;

procedure insert(var t:longint;v:int64);
begin
  if t=0 then begin
    inc(tot);
    t:=tot;
    key[t]:=v;
    s[t]:=1;
    left[t]:=0;
    right[t]:=0;
  end
  else begin
    inc(s[t]);
    if v<key[t] then insert(left[t],v)
      else insert(right[t],v);
    maintain(t);
  end;
end;

function delete(var t:longint;v:int64):int64;
begin
  dec(s[t]);
  if (key[t]=v) or( (v<key[t]) and (left[t]=0) )or ((v>=key[t]) and (right[t]=0)) then begin
    delete:=key[t];
    if (left[t]=0) or (right[t]=0) then
      t:=left[t]+right[t]
    else key[t]:=delete(left[t],key[t]+1);
  end
  else
    if v<key[t] then
      delete:=delete(left[t],v)
    else delete:=delete(right[t],v);
end;

function searchmin(var t:longint):int64;
begin
  if left[t]=0 then exit(key[t]);
  exit(searchmin(left[t]));
end;

function into:boolean;
begin
  readln(n,m);
  sum[0]:=0;
  for i:=1 to n do begin
    read(a[i]);
    sum[i]:=sum[i-1]+a[i];
    if a[i]>m then exit(false);
  end;
  exit(true);
end;

begin
  if into then begin
    t:=0;
    tot:=0;
    head:=1;
    tail:=1;
    deci:=0;
    for i:=1 to n do begin
      while sum[i]-sum[deci]>m do inc(deci);
      while (head<tail) and (q[head]<=deci) do begin
        delete(t,f[d[head]]+a[q[head]]);
        inc(head);
      end;
      while (head<tail) and (a[i]>=a[q[tail-1]]) do begin
        delete(t,f[d[tail-1]]+a[q[tail-1]]);
        dec(tail);
      end;
      q[tail]:=i;
      if head<tail then
        d[tail]:=q[tail-1]
      else d[tail]:=deci;
      insert(t,f[d[tail]]+a[i]);
      inc(tail);
      if d[head]<deci then begin
        delete(t,f[d[head]]+a[q[head]]);
        d[head]:=deci;
        insert(t,f[deci]+a[q[head]]);
      end;
      f[i]:=searchmin(t);
    end;
    writeln(f[n]);
  end
    else writeln(‘-1‘);
  readln;
  readln;
end.

时间: 2024-12-25 23:56:07

【以前的空间】Poj 3071 Cut the Sequence的相关文章

poj 3017 Cut the Sequence

poj 3017 Cut the Sequence 单调队列 题意是:把一个 长度 为 n 的 数列 分成任意份,使每一份的和不超过m,求每一份的最大值的和,使和最小 动态规划方程 是 f [i] = f[j] + max{ f[j+1] , f[j+2] , f[i] }; 朴素的算法是 O(n^2); 用 单调队列 表示一个递减 的 队列 ,则 不需要 求 每块区域的最大值 哎哎哎……不知道怎么说 #include <iostream> #include <cstdio> #i

POJ 3017 Cut the Sequence (单调队列优化DP)

POJ 3017 Cut the Sequence (单调队列优化DP) ACM 题目地址: POJ 3017 Cut the Sequence 题意: 将一个由N个数组成的序列划分成若干段,要求每段数字的和不超过M,求[每段的最大值]的和 的最小的划分方法,输出这个最小的和. 分析: 方程是:dp[i] = min(dp[j]+maxsum[j+1][i]) 但复杂度n*n太高,需要优化. 可以用单调队列+BST优化,其实只需要维护每一段的最大值. 看了这篇题解的:http://blog.cs

poj 3017 Cut the Sequence(单调队列优化 )

题目链接:http://poj.org/problem?id=3017 题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小 分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m 这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =) 然后是优化了,首先当然是要优化一个最大

POJ 2081 Recaman&#39;s Sequence

比较简单,加一个B数组判重即可 Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 21743   Accepted: 9287 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already i

POJ 3071 Football(简单 概率DP)

Football 原文链接:http://blog.csdn.net/xuechelingxiao/article/details/38520105 大意:2^n 个球队进行单场淘汰赛,每两只球队之间比赛会有胜负的概率,问最后谁夺冠的概率最大. 思路:简单的概率DP问题,主要是怎么处理哪两个球队比赛的问题. DP方程为 dp[i][j] = ∑(dp[i-1][j]*dp[i-1][k]*p[j][k]); //dp[i][j]表示第 i 轮的时候,第 j 支队伍赢的概率.. 对于其中位运算,可

【POJ】2278 DNA Sequence

各种wa后,各种TLE.注意若AC非法,则ACT等一定非法.而且尽量少MOD. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 7 #define MAXN 105 8 #define NXTN 4 9 10 char str[15]; 11 12 typedef struct Matrix {

poj Problem A. Score Sequence(暴力)

这道题,对于我这种英文不好的人来说,有点费劲啊. 题目的意思:给你两组成绩,你要找出他们之间最大的公共子序列,不能有重复,然后输出两组数据. 第一组就是:按照从大到小输出最大子序列. 第二组就是:按照个位数由小到大输出,若个位数一样大,则小的在前输出最大子序列. 解题思路基本上已经出来了,就是千万要注意就是在最长子序列匹配之前就就把重复的数字给删除. 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h

POJ 3071 Football (动态规划-概率DP)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2768   Accepted: 1412 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

poj 2081 Recaman&#39;s Sequence (dp)

Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 22566   Accepted: 9697 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already in the sequence,