CF #271 div2

2014-10-07 18:33:08

思路:6题场,真激情~因为unrated,水过D就滚粗了QAQ。A、B、C没搞,听说C是个裸暴力,卡long long 0.0。

D:不多说了,dp转移方程:dp[i] = dp[i - 1] + dp[i - k]

E:离散化后用线段树维护一个DP,因为有输出路径的存在而变得巨坑。。。先将所有高度离散化,然后根据离散化后的数组建树,节点存的是这个高度区间内的最大dp值。在dp的时候,设考虑dp[i],那么在线段树中查询[1,hi - d] , [hi + d,tree_size]内的最大值,算出dp[i]后更新线段树,因为dp值是一个一个加入树中的,所以比较方便。要注意的是在记录路径的时候是记录离该点最近的max(dp[j]) (j < i),所以位置映射数组要即使更新!(见97行),被这个坑地RE到死啊QAQ。

  1 /*************************************************************************
  2     > File Name: e.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com
  5     > Created Time: Tue 07 Oct 2014 01:05:56 AM CST
  6 ************************************************************************/
  7 #include <cstdio>
  8 #include <cstring>
  9 #include <cstdlib>
 10 #include <cmath>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <queue>
 15 #include <iostream>
 16 #include <algorithm>
 17 using namespace std;
 18 #define lp (p << 1)
 19 #define rp (p << 1|1)
 20 #define getmid(l,r) (l + (r - l) / 2)
 21 #define MP(a,b) make_pair(a,b)
 22 typedef long long ll;
 23 const int INF = 1 << 30;
 24 const int maxn = 100010;
 25 
 26 int n,pa[maxn],ah[maxn],pre,ansmax;
 27 ll h[maxn],bh[maxn],d;
 28 
 29 struct node{
 30     int tmax,id;
 31 }t[maxn << 2];
 32 
 33 void Query_max(int a,int b,int p,int l,int r){
 34     if(a <= l && r <= b){
 35         if(t[p].tmax > ansmax){
 36             ansmax = t[p].tmax;
 37             pre = t[p].id;
 38         }
 39         return;
 40     }
 41     int mid = getmid(l,r);
 42     if(a <= mid) Query_max(a,b,lp,l,mid);
 43     if(b > mid) Query_max(a,b,rp,mid + 1,r);
 44 }
 45 
 46 void Update(int a,int v,int p,int l,int r){
 47     if(l == r){
 48         t[p].tmax = v;
 49         return;
 50     }
 51     int mid = getmid(l,r);
 52     if(a <= mid) Update(a,v,lp,l,mid);
 53     else Update(a,v,rp,mid + 1,r);
 54     t[p].tmax = max(t[lp].tmax,t[rp].tmax);
 55     if(t[p].tmax == t[lp].tmax) t[p].id = t[lp].id;
 56     else t[p].id = t[rp].id;
 57 }
 58 
 59 void Build_tree(int p,int l,int r){
 60     t[p].tmax = 0;
 61     if(l == r){
 62         t[p].id = l;
 63         return;
 64     }
 65     int mid = getmid(l,r);
 66     Build_tree(lp,l,mid);
 67     Build_tree(rp,mid + 1,r);
 68 }
 69 
 70 void Print(int p){
 71     if(pa[p] == 0){
 72         printf("%d",p);
 73         return;
 74     }
 75     if(pa[p]) Print(pa[p]);
 76     printf(" %d",p);
 77 }
 78 
 79 int main(){
 80     scanf("%d%I64d",&n,&d);
 81     for(int i = 1; i <= n; ++i){
 82         scanf("%I64d",h + i);
 83         bh[i] = h[i];
 84     }
 85     sort(bh + 1,bh + (ll)n + 1);
 86     int sz = unique(bh + 1,bh + (ll)n + 1) - bh - 1;
 87     Build_tree(1,1,sz);
 88     for(int i = 1; i <= n; ++i){
 89         int l = upper_bound(bh + 1,bh + (ll)sz + 1,h[i] - d) - bh;
 90         int r = lower_bound(bh + 1,bh + (ll)sz + 1,h[i] + d) - bh;
 91         ansmax = -1;
 92         if(r <= sz) Query_max(r,sz,1,1,sz);
 93         if(1 <= l - 1) Query_max(1,l - 1,1,1,sz);
 94         int pos = lower_bound(bh + 1,bh + (ll)sz + 1,h[i]) - bh;
 95         Update(pos,ansmax + 1,1,1,sz);
 96         pa[i] = ah[pre];
 97         ah[pos] = i;
 98     }
 99     printf("%d\n",t[1].tmax);
100     Print(ah[t[1].id]);
101     puts("");
102     return 0;
103 }

F:这题反而比E简单,用线段树维护区间内所有数的gcd值,发现区间内满足条件的情况只可能是区间gcd == 区间最小值,答案就是区间长度 - 最小值个数。所以开两棵线段树,一棵维护区间gcd值,一棵区间最小值及其个数。

 1 By suda1327405059, contest: Codeforces Round #271 (Div. 2), problem: (F) Ant colony, Accepted, #
 2  /*************************************************************************
 3     > File Name: f.cpp
 4     > Author: Nature
 5     > Mail: 564374850@qq.com 
 6     > Created Time: Tue 07 Oct 2014 01:45:42 AM CST
 7 ************************************************************************/
 8 
 9 #include <cstdio>
10 #include <cstring>
11 #include <cstdlib>
12 #include <cmath>
13 #include <vector>
14 #include <map>
15 #include <set>
16 #include <queue>
17 #include <iostream>
18 #include <algorithm>
19 using namespace std;
20 #define lp (p << 1)
21 #define rp (p << 1|1)
22 #define getmid(l,r) (l + (r - l) / 2)
23 #define MP(a,b) make_pair(a,b)
24 typedef long long ll;
25 const int INF = 1 << 30;
26 const int maxn = 100010;
27 
28 int Gcd(int a,int b){ return b == 0 ? a : Gcd(b,a % b);}
29 
30 int n,q;
31 int    s[maxn];
32 struct node{
33     int num;
34     int g,tmin;
35 }t[maxn << 2];
36 
37 void Build_tree(int p,int l,int r){
38     t[p].num = 0;
39     if(l == r){
40         t[p].g = t[p].tmin = s[l];
41         t[p].num = 1;
42         return;
43     }
44     int mid = getmid(l,r);
45     Build_tree(lp,l,mid);
46     Build_tree(rp,mid + 1,r);
47     t[p].g = Gcd(t[lp].g,t[rp].g);
48     t[p].tmin = min(t[lp].tmin,t[rp].tmin);
49     if(t[p].tmin == t[lp].tmin) t[p].num += t[lp].num;
50     if(t[p].tmin == t[rp].tmin) t[p].num += t[rp].num;
51 }
52 
53 int Query_min(int a,int b,int v,int p,int l,int r){
54     if(a <= l && r <= b){
55         if(t[p].tmin == v) return t[p].num;
56         else return 0;
57     }
58     int mid = getmid(l,r),res = 0;
59     if(a <= mid) res += Query_min(a,b,v,lp,l,mid);
60     if(b > mid) res += Query_min(a,b,v,rp,mid + 1,r);
61     return res;
62 }
63 
64 int Query_gcd(int a,int b,int p,int l,int r){
65     if(a <= l && r <= b)
66         return t[p].g;
67     int res = -1,mid = getmid(l,r);
68     if(a <= mid) res = Query_gcd(a,b,lp,l,mid);
69     if(b > mid){
70         if(res == -1) res = Query_gcd(a,b,rp,mid + 1,r);
71         else res = Gcd(res,Query_gcd(a,b,rp,mid + 1,r));
72     }
73     return res;
74 }
75 
76 int Find(int a,int b){
77     int G = Query_gcd(a,b,1,1,n);
78     return Query_min(a,b,G,1,1,n);
79 }
80 
81 int main(){
82     int a,b;
83     scanf("%d",&n);
84     for(int i = 1; i <= n; ++i)
85         scanf("%d",s + i);
86     Build_tree(1,1,n);
87     scanf("%d",&q);
88     for(int i = 1; i <= q; ++i){
89         scanf("%d%d",&a,&b);
90         printf("%d\n",b - a + 1 - Find(a,b));
91     }
92     return 0;
93 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4009659.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值