CF1039E Summer Oenothera Exhibition

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/82806936

原题链接:http://codeforces.com/contest/1039/problem/E

Summer Oenothera Exhibition

While some people enjoy spending their time solving programming contests, Dina prefers taking beautiful pictures. As soon as Byteland Botanical Garden announced Summer Oenothera Exhibition she decided to test her new camera there.

The exhibition consists of l = 1 0 100 l=10^{100} Oenothera species arranged in a row and consecutively numbered with integers from 0 0 to l 1 l−1 . Camera lens allows to take a photo of w w species on it, i.e. Dina can take a photo containing flowers with indices from x x to x + w 1 x+w−1 for some integer x x between 0 0 and l w l−w . We will denote such photo with [ x , x + w 1 ] [x,x+w−1] .

She has taken n n photos, the i i -th of which (in chronological order) is [ x i , x i + w 1 ] [x_i,x_i+w−1] in our notation. She decided to build a time-lapse video from these photos once she discovered that Oenothera blossoms open in the evening.

Dina takes each photo and truncates it, leaving its segment containing exactly k k flowers, then she composes a video of these photos keeping their original order and voilà, a beautiful artwork has been created!

A scene is a contiguous sequence of photos such that the set of flowers on them is the same. The change between two scenes is called a cut. For example, consider the first photo contains flowers [ 1 , 5 ] [1,5] , the second photo contains flowers [ 3 , 7 ] [3,7] and the third photo contains flowers [ 8 , 12 ] [8,12] . If k = 3 k=3 , then Dina can truncate the first and the second photo into [ 3 , 5 ] [3,5] , and the third photo into [ 9 , 11 ] [9,11] . First two photos form a scene, third photo also forms a scene and the transition between these two scenes which happens between the second and the third photos is a cut. If k = 4 k=4 , then each of the transitions between photos has to be a cut.

Dina wants the number of cuts to be as small as possible. Please help her! Calculate the minimum possible number of cuts for different values of k k .

Input

The first line contains three positive integer n , w , q ( 1 n , q 100000 , 1 w 1 0 9 ) n, w, q (1≤n,q≤100000, 1≤w≤10^9) — the number of taken photos, the number of flowers on a single photo and the number of queries.

Next line contains n n non-negative integers x i ( 0 x i 1 0 9 ) x_i (0≤x_i≤10^9) — the indices of the leftmost flowers on each of the photos.

Next line contains q q positive integers k i ( 1 k i w ) k_i (1≤k_i≤w) — the values of k k for which you have to solve the problem.

It’s guaranteed that all k i k_i are distinct.

扫描二维码关注公众号,回复: 3416775 查看本文章
Output

Print q q integers — for each width of the truncated photo k i k_i , the minimum number of cuts that is possible.

Examples
input

3 6 5
2 4 0
1 2 3 4 5

output

0
0
1
1
2

input

6 4 3
1 2 3 4 3 2
1 2 3

output

0
1
2

题目大意

直接看英文是真的不知道在说个什么**玩意儿,但是修修告诉我题意是这样的:

给定长度为 n n 的序列,常数 w w ,询问次数 q q

接下来 q q 组询问,每次给出一个常数 k i k_i ,求最少把序列分为多少段使得每段序列中数的极差不超过 w k i w-k_i ,输出最小的段数 1 -1

题解

让我们先考虑一下单次询问怎么做:直接贪心,每次尽量往后跳,直到极差不满足条件为止,这样我们就 O ( n ) O(n) 解决了一次询问。

暴力跳太 l o w \mathcal{low} 了,不如我们倍增吧,先处理出最大/最小值的 S T \mathcal{ST} 表,我们就可以愉快的倍增往后跳了。

在线一看就很不可做的样子,那就把所有询问单增离线吧,离线之后,跳的距离也会单增,考虑维护每个点向后能跳到的最远点 n x t [ v ] nxt[v]

暴力一点的做法:对于一个新的极差 r r ,我们把所有点都尝试往后挪来更新 n x t [ v ] nxt[v] ,然后从头开始往后沿着 n x t [ v ] nxt[v] 跳。

感觉这个操作修改和查询都很爆炸,自然想到分块一下,块内路径压缩,更新路径也仅限于块内,块之间跳用倍增来找。

复杂度?大概是 O ( n 3 2 log 2 n ) O(n^{\frac{3}{2}}\log_2n) 的吧。

据说修修有个 O ( O ( n 5 3 + n 4 3 log n ) ) O(O(n^{\frac{5}{3}} + n^{\frac{4}{3}}\log n)) 的优秀做法,然而我DZYO O ( n 3 2 log 2 n ) O(n^{\frac{3}{2}}\log_2n) C F CF 最快,一手 L C T \mathcal{LCT} 弹飞绵羊代替路径压缩跑的飞快,吊锤所有算法。

代码

S T \mathcal{ST} 表表示 2 i 2^i 的维度一定要开在前面,这样就能访问连续内存,这大概就是 A C \mathcal{AC} T L E \mathcal{TLE} 的距离吧。

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
struct sd{int id,r;}ask[M<<6];
bool operator <(sd a,sd b){return a.r==b.r?a.id>b.id:a.r<b.r;}
int st[20][M][2],que[M],nxt[M],blo[M][2],jmp[M][2],ans[M],n,w,q,siz,tot;
void in()
{
	scanf("%d%d%d",&n,&w,&q);
	for(int i=1;i<=n;++i)scanf("%d",&que[i]),st[0][i][0]=st[0][i][1]=que[i];
	for(int i=1,k;i<=q;++i)scanf("%d",&k),ask[++tot]=(sd){i-q,w-k};
}
void up(int v){(nxt[v]==n+1||(nxt[v]-1)%siz==0)?(jmp[v][0]=1,jmp[v][1]=v):(jmp[v][0]=jmp[nxt[v]][0]+1,jmp[v][1]=jmp[nxt[v]][1]);}
void ac()
{
	for(;siz*siz*siz<6*n;++siz);
	for(int j=1;(1<<j)<=n;++j)for(int i=1;i+(1<<j)<=n+1;++i)
	st[j][i][0]=min(st[j-1][i][0],st[j-1][i+(1<<j-1)][0]),
	st[j][i][1]=max(st[j-1][i][1],st[j-1][i+(1<<j-1)][1]);
	for(int i=n;i>=1;--i)
	{
		nxt[i]=i+1,blo[i][0]=blo[i][1]=que[i],up(i);
		for(int j=i+1,mn=que[i],mx=que[i];j<=n&&(j-1)%siz>0;++j)mn=min(mn,que[j]),mx=max(mx,que[j]),ask[++tot]=(sd){i,mx-mn};
	}
	sort(ask+1,ask+1+tot);
	for(int i=1,pos,cst,mn,mx,k,to,maxn,minn;i<=tot;++i)
	if(ask[i].id<=0)for(pos=1,cst=-1;pos<=n;ans[ask[i].id+q]=cst)
	{
		cst+=jmp[pos][0],pos=jmp[pos][1],mn=blo[pos][0],mx=blo[pos][1],to=pos,k=0;
		for(;pos+(1<<k)<=n+1&&(maxn=max(mx,st[k][pos][1]))-(minn=min(mn,st[k][pos][0]))<=ask[i].r;++k)mx=maxn,mn=minn;
		for(;k--;)if(to+(1<<k)<=n+1&&(maxn=max(mx,st[k][to][1]))-(minn=min(mn,st[k][to][0]))<=ask[i].r)mx=maxn,mn=minn,to+=1<<k;
		blo[pos][0]=mn,blo[pos][1]=mx,pos=nxt[pos]=to;
	}
	else for(nxt[pos=ask[i].id]++,mn=(pos-1)/siz*siz+1;pos>=mn;--pos)up(pos);
	for(int i=1;i<=q;++i)printf("%d\n",ans[i]);
}
int main(){in();ac();}

寻找一个能读懂这份玄学代码的人(来源)。

#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

# include <iostream>
# include <immintrin.h>
# include <array>
using namespace std;

constexpr int INF = 1e9 + 9;
int x[101010];
int n, w, q;
using V4 = int __attribute__ ((vector_size (16)));
#define MAX(a, b) __builtin_ia32_pmaxsd128(a, b)
#define MIN(a, b) __builtin_ia32_pminsd128(a, b)
V4 foo(V4 k) {
    V4 from = {-INF, -INF, -INF, -INF};
    V4 to = from;
    V4 ans = {-1, -1, -1, -1};
    for (int i = 0; i < n; ++i) {
        V4 val = {x[i], x[i], x[i], x[i]};
        from = MAX(from, val);
        to = MIN(to, val);
        V4 c = from > to + k;
        ans -= c;
        from += c & (val - from);
        to += c & (val - to);
    }
    return ans;
}

int main() 
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n >> w >> q;
    for (int i = 0; i < n; ++i) {cin >> x[i];}
    while (q > 0) 
    {
        int kk[4];
        V4 k;
        for (int i = 0; i < 4; ++i) {cin >> kk[i];}
        for (int i = 0; i < 4; ++i) {k[i] = w - kk[i];}
        auto ans = foo(k);
        for (int i = 0; i < min(q, 4); ++i) {cout << ans[i] << '\n';}
        q -= 4;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/82806936