codeforces 278Div1 B题

虚拟参赛的时候没想到是线段树,看到很多人都过了,也蛮着急的。

首先用二分+线段树的方法更新DP[i]:它表示以A[i]为结尾可以最前到哪个位置;

再用线段树计算ans[i]:它表示当前i个A元素可以最少分成多少个pieces,ans[i]=1+min(ans[j]),dp[i]-1<=j<=i-L。

over.

16 #define N 100000+5
 17
 18 int a[N],dp[N],Ans[N];
 19 struct segment {
 20     int l,r;
 21     int Min,Max,ans;
 22 } seg[4*N];
 23
 24 struct diff {
 25     int Max,Min;
 26     diff(int x=0,int n=0):Max(x),Min(n) {}
 27 };
 28
 29 void build(int p,int l,int r)
 30 {
 31     seg[p].l=l, seg[p].r=r, seg[p].ans=-1;;
 32     if (l==r) {
 33         seg[p].Min = seg[p].Max = a[l];
 34         return;
 35     }
 36     build(p<<1,l,(l+r)>>1);
 37     build((p<<1)+1,((l+r)>>1)+1,r);
 38
 39     seg[p].Min = min(seg[p<<1].Min, seg[(p<<1)+1].Min),
 40     seg[p].Max = max(seg[p<<1].Max, seg[(p<<1)+1].Max);
 41 }
 42
 43 diff query1(int p,int l,int r)
 44 {
 45     if (l<=seg[p].l && seg[p].r<=r) {
 46         return diff(seg[p].Max,seg[p].Min);
 47     }
 48
 49     diff t1,t2;
 50     bool f1=false, f2=false;
 51     if (seg[p<<1].r>=l)
 52         f1=true, t1=query1(p<<1,l,r);
 53     if (seg[(p<<1)+1].l<=r)
 54         f2=true, t2=query1((p<<1)+1,l,r);
 55
 56     if (f1) {
 57         if (f2)
 58             return diff(max(t1.Max,t2.Max), min(t1.Min,t2.Min));
 59         else
 60             return t1;
 61     }
 62     else
 63         if (f2)
 64             return t2;
 65     return diff(0,0);
 66 }
 67
 68 int query2(int p,int l,int r)
 69 {
 70     if (l<=seg[p].l && seg[p].r<=r) {
 71         return seg[p].ans;
 72     }
 73
 74     int t1=-1,t2=-1;
 75     if (seg[p<<1].r>=l)
 76         t1=query2(p<<1,l,r);
 77     if (seg[(p<<1)+1].l<=r)
 78         t2=query2((p<<1)+1,l,r);
 79
 80     if (t1==-1) {
 81         return t2;
 82     }
 83     else {
 84         if (t2==-1)
 85             return t1;
 86         else return min(t1,t2);
 87     }
 88
 89 }
 90
 91 void add(int p,int i,int newans)
 92 {
 93     if (seg[p].l==seg[p].r) {
 94         seg[p].ans=newans;
 95         return;
 96     }
 97
 98     if (i<=seg[p<<1].r)
 99         add(p<<1,i,newans);
100     else
101         add((p<<1)+1,i,newans);
102
103     if (seg[p<<1].ans==-1) {
104         seg[p].ans = seg[(p<<1)+1].ans;
105     }
106     else {
107         if (seg[(p<<1)+1].ans==-1)
108             seg[p].ans=seg[p<<1].ans;
109         else
110             seg[p].ans=min(seg[p<<1].ans,seg[(p<<1)+1].ans);
111     }
112 }
113
114 int main()
115 {
116     //freopen("b.txt","r",stdin);
117
118     int n,s,l;
119     cin>>n>>s>>l;
120     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
121     build(1,1,n);
122     for (int i=1;i<=n;i++) {
123         int L=1,R=i-1;
124         dp[i]=i;
125         while (L<=R) {
126             int mid = (L+R)>>1;
127             diff tmp = query1(1,mid,i);
128             if (tmp.Max-tmp.Min<=s) {
129                 R=mid-1;
130                 dp[i]=mid;
131             }
132             else {
133                 L=mid+1;
134             }
135         }
136     }
137
138
139     for (int i=1;i<=n;i++) {
140         if (i<l) {
141             Ans[i]=-1;
142             continue;
143         }
144         int tmp=-1;
145         if (i-l>0 && dp[i]-1<=i-l)
146             tmp=query2(1,max(1,dp[i]-1),i-l);
147         if (dp[i]==1) tmp=0;
148
149         if (tmp==-1)
150             Ans[i]=-1;
151         else
152             Ans[i]=tmp+1, add(1,i,Ans[i]);
153     }
154     cout<<Ans[n]<<endl;
155
156     return 0;
157 }
时间: 2024-08-11 02:28:49

codeforces 278Div1 B题的相关文章

Codeforces VP/补题小记 (持续填坑)

Codeforces VP/补题小记 1149 C. Tree Generator 给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径. ? 考虑括号序列维护树的路径信息和,是将左括号看做 \(-1\) ,右括号看做 \(1\) ,那么一段竖直向上的路径可以表示为括号序列的一个区间和,一段竖直向下的路径可以看做括号序列的一个区间和的相反数.我们要维护的是树的直径,也就是一段连续的和减去紧随其后的一段连续的差.具体来说就是 \[ \max_{\forall [l,r]}\{\sum_{

CodeForces - 427B (模拟题)

Prison Transfer Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Submit Status Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c of t

codeforces 984补题

codeforces 984a 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int num[1010]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) scanf("%d",&num[i]); 8 sort(num+1,num+n+1); 9 if(n%2==1) printf("%

codeforces 乱做题记录

Codeforces 590 E https://codeforces.com/problemset/problem/590/E 给 $ n $ 个只包含字符 $ a $ 和 $ b $ 的字符串,总长度不超过 $ 10^7 $,选出最多的字符串,使得其中不存在字符串 $ a $ 和 $ b $ 满足 $ a $ 是 $ b $ 的子串,输出方案,如果有多种方案,输出任意一种 $ n \le 750 $ 我们需要对每个串求出所有的比它短的是它的子串的字符串,并向其连边,可以发现这 $ n $ 个

B - Save the problem! CodeForces - 867B 构造题

B - Save the problem! CodeForces - 867B 这个题目还是很简单的,很明显是一个构造题,但是早训的时候脑子有点糊涂,想到了用1 2 来构造, 但是去算这个数的时候算错了... 用1 2 来构造 可以先枚举一些数来找找规律. 1 1 2 2 3 1 1 1    2 1 1 4 .... 可以发现每一个数都是 n/2+1 的可能, 所以反过来推过去就是 (s-1)*2  或者(s-1)*2+1 这个(s-1)*2+1的答案才是正确答案 因为 这个s可以==1 #i

codeforces打完补题

https://codeforces.com/contest/1234/problem/D 写了个巨蠢的线段树(不愧是垃圾),有必要提醒下自己这种题怎么做 #include<iostream> #include<cstdio> #include<string> #include<set> #include<algorithm> using namespace std; const int maxn = 32; set<int> st[

Codeforces Hello2015第一题Cursed Query

英文题面: De Prezer loves movies and series. He has watched the Troy for like 100 times and also he is a big fan of Supernatural series.So, he did some researches and found a cursed object which had n lights on it and initially all of them were turned of

codeforces 399D Pages-yy题

题意:模拟一个网页的跳转按钮,当前页为p,左右显示的页号为p-k,p+k,当前页为1时没有左箭头,当前页为n时没有右箭头,显示的页号必须合法(在1~n之间) 分析:按照条件直接做.这种题最主要的就是细心. 代码: #include<iostream> #include<cstdio> #include<algorithm> #define min(a,b) a<b?a:b #define INF 1000000007 using namespace std; in

Codeforces 802 补题

A 水题 同B #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; const int maxn=1000000; int n,k,a[maxn],num; bool ex[maxn],need[maxn]; int main() {//freopen("t.txt","r",stdin); scanf("%d%d"