codeforces332B - Maximum Absurdity 线段数 or dp

题意:给你一个序列,找两个长度为 k 且没有重合区间的数使得其和最大

解题思路:

1)线段树

想了半天想不出只能先用线段树撸了一发,这题dp 第一名只要了 9分钟。

就是把起点为 i  长度为 k 的和预处理出来,再用线段树枚举去找。

解题代码:

  1 // File Name: 332b.cpp
  2 // Author: darkdream
  3 // Created Time: 2014年07月30日 星期三 08时10分45秒
  4
  5 #include<vector>
  6 #include<list>
  7 #include<map>
  8 #include<set>
  9 #include<deque>
 10 #include<stack>
 11 #include<bitset>
 12 #include<algorithm>
 13 #include<functional>
 14 #include<numeric>
 15 #include<utility>
 16 #include<sstream>
 17 #include<iostream>
 18 #include<iomanip>
 19 #include<cstdio>
 20 #include<cmath>
 21 #include<cstdlib>
 22 #include<cstring>
 23 #include<ctime>
 24 #define LL long long
 25 using namespace std;
 26 #define M 200004
 27 struct node{
 28   int l , r ,m;
 29   LL maxn,s;
 30 }tree[M <<2];
 31 LL a[200004];
 32 LL sum[200004];
 33 int L(int x)
 34 {
 35   return 2 * x;
 36 }
 37 int R(int x)
 38 {
 39    return 2 * x + 1;
 40 }
 41 void  pushup(int c)
 42 {
 43    if(tree[L(c)].maxn >=tree[R(c)].maxn)
 44    {
 45       tree[c].maxn = tree[L(c)].maxn;
 46       tree[c].s = tree[L(c)].s;
 47    }else{
 48       tree[c].maxn = tree[R(c)].maxn;
 49       tree[c].s = tree[R(c)].s;
 50    }
 51 }
 52 void build(int c ,int l, int r)
 53 {
 54       tree[c].l = l ;
 55       tree[c].r = r ;
 56       tree[c].m = (l+r)/2;
 57       if(l == r)
 58       {
 59         tree[c].maxn = sum[l];
 60         tree[c].s = l ;
 61         return ;
 62       }
 63       build(L(c),l,tree[c].m);
 64       build(R(c),tree[c].m+1,r);
 65       pushup(c);
 66 }
 67 LL maxa;
 68 int site;
 69 void find(int c, int l , int r)
 70 {
 71     //printf("%d %d %d %d %d\n",c,tree[c].l,tree[c].r,l,r);
 72      if(r <  l )
 73          return ;
 74      if(l <= tree[c].l && r >= tree[c].r)
 75      {
 76          if(tree[c].maxn > maxa)
 77          {
 78            maxa = tree[c].maxn;
 79            site = tree[c].s;
 80          }
 81          return ;
 82      }
 83      if(l <= tree[c].m)
 84          find(L(c),l,r);
 85      if(r > tree[c].m)
 86          find(R(c),l,r);
 87 }
 88 int main(){
 89    int n , k;
 90    scanf("%d %d",&n,&k);
 91    int temp ;
 92    a[0] = 0 ;
 93    for(int i = 1; i <= n;i ++)
 94    {
 95        scanf("%d",&temp);
 96        a[i] = a[i-1] + temp;
 97    }
 98    for(int i = 1 ;i <= n-k+1; i ++)
 99    {
100       sum[i] = a[i+k-1] - a[i-1];
101    }
102    build(1,1,n-k+1);
103    LL  ans = -1e9;
104    int a, b ;
105    for(int i =1 ;i <= n-k+1;i ++)
106    {
107       maxa = -1e9 ;
108       site = 0 ;
109       find(1,i+k,n-k+1);
110       if(sum[i] + maxa > ans)
111       {
112           ans  = sum[i] + maxa;
113           a= i ;
114           b = site;
115       }
116    }
117    printf("%d %d\n",a,b);
118 return 0;
119 }

2)由第一种思路突然想到还可以预处理出来 i 以后 的最大值是多少,位置是多少,这样就可以直接dp了

 1 // File Name: 332b.1.cpp
 2 // Author: darkdream
 3 // Created Time: 2014年07月30日 星期三 10时13分41秒
 4
 5 #include<vector>
 6 #include<list>
 7 #include<map>
 8 #include<set>
 9 #include<deque>
10 #include<stack>
11 #include<bitset>
12 #include<algorithm>
13 #include<functional>
14 #include<numeric>
15 #include<utility>
16 #include<sstream>
17 #include<iostream>
18 #include<iomanip>
19 #include<cstdio>
20 #include<cmath>
21 #include<cstdlib>
22 #include<cstring>
23 #include<ctime>
24 #define LL long long
25 #define maxn 200050
26 using namespace std;
27 LL a[maxn];
28 LL sum[maxn];
29 LL m[maxn];
30 int s[maxn];
31 int n , k ;
32 int main(){
33      scanf("%d %d",&n,&k);
34      a[0] = 0 ;
35      int temp ;
36      for(int i = 1;i <=  n;i ++)
37      {
38         scanf("%d",&temp);
39         a[i] =a[i-1]+ temp;
40      }
41      int p = n - k + 1;
42      for(int i = 1;i <= p ; i ++)
43      {
44        sum[i] = a[i+k-1] - a[i-1];
45      }
46      m[p] = sum[p];
47      s[p] = p ;
48
49      for(int i = p -1;i >= 1 ;i --)
50      {
51         if(sum[i] >= m[i+1])
52         {
53             m[i] = sum[i];
54             s[i] = i ;
55         }else{
56            m[i] = m[i+1];
57            s[i] = s[i+1];
58         }
59      }
60      int a, b ;
61      LL maxa = -1e9 ;
62      for(int i =1 ;i <= p;i ++)
63      {
64         if(sum[i] + m[i+k] > maxa)
65         {
66            a = i ;
67            b = s[i+k];
68            maxa = sum[i] + m[i+k];
69         }
70      }
71      printf("%d %d\n",a,b);
72 return 0;
73 }

codeforces332B - Maximum Absurdity 线段数 or dp

时间: 2024-10-01 22:37:09

codeforces332B - Maximum Absurdity 线段数 or dp的相关文章

hdu 4719 Oh My Holy FFF(线段数+dp)

题目链接:hdu 4719 Oh My Holy FFF 题目大意:队伍里有n个人,给出每个人的身高,他们按照顺序排列,现在要将这n个人分成若干组,每一组的人数不得大于l,并且第i组的最后一个人的身高一定要大于第i?1组的最后一个人的身高.要求最后的权值最大,权值计算方法在题目中,k为组号. 解题思路:dp[i]表示以第i个人作为结尾的最大权值,那么dp[i]肯定是从前面的l-1个中转移过来的,即dp[i]=dp[j]+h[i]2?h[j] 要求h[i]>h[j]. 但是这样的复杂度为o(n2)

【POJ 2750】 Potted Flower(线段树套dp)

[POJ 2750] Potted Flower(线段树套dp) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4566   Accepted: 1739 Description The little cat takes over the management of a new park. There is a large circular statue in the center of the park, surrou

【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a variant of the game for themselves to play. Being played by clumsy animals weighing nearly a ton, Cow Hopscotch almost always ends in disaster, but this has

hdu1754(线段数维护区间最大值)

题意:给定1-n(n<=200000)个数,然后动态改变一些值,并动态询问区间最大值. 解法:裸的线段树,赛前默写模版回忆下线段树代码.仍然要注意:线段树节点数组一定要开到节点数的三倍长度. 代码: /****************************************************** * author:xiefubao *******************************************************/ #pragma comment(lin

poj 3264 Balanced Lineup(线段数求区间最大最小值)

链接:http://poj.org/problem?id=3264 Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 32772   Accepted: 15421 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order.

cf 11D A Simple Task(数压DP)

题意: N个点构成的无向图,M条边描述这个无向图. 问这个无向图中共有多少个环. (1 ≤ n ≤ 19, 0 ≤ m) 思路: 例子: 4 6 1 2 1 3 1 4 2 3 2 4 3 4 答案:7 画个图发现,直接暴力DFS有太多的重复计算.用DP. 枚举点数(状态),每个状态的起点.终点(起点可以不用枚举,因为反正是一个环,谁作为起点都一样). dp[S][i]:状态是S,i是终点   含义:从S中的第一个数s出发到达第i个点的方案数.如果s和i相加,总方案数ans+=dp[S][i]

线段数 --- (单点更新、求逆序对)

Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For

BZOJ 1835 基站选址(线段树优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1835 题意:有N个村庄坐落在一条直线上,第 i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村 庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位 置,使得总费用最小. 思路: 另外,程序中的n=n+1,m=

HDU 2048 数塔(DP)

数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 20786    Accepted Submission(s): 12486 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少