CF1748E Yet Another Array Counting Problem
Posted tanjunming2020
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1748E Yet Another Array Counting Problem相关的知识,希望对你有一定的参考价值。
CF1748E Yet Another Array Counting Problem
题目大意
对于一个长度为 n n n的序列 x x x,其在区间 [ l , r ] [l,r] [l,r]的最左端最大值位置为满足 l ≤ i ≤ r l\\leq i\\leq r l≤i≤r且 x i = max j = l r x j x_i=\\max\\limits_j=l^rx_j xi=j=lmaxrxj的最小的整数 i i i。
给定两个整数 n , m n,m n,m和一个长度为 n n n的序列 a a a,求满足下列条件的序列 b b b的数量:
- 序列 b b b的长度为 n n n,且对于任意整数 i ( 1 ≤ i ≤ n ) i(1\\leq i\\leq n) i(1≤i≤n)都有 1 ≤ b i ≤ m 1\\leq b_i\\leq m 1≤bi≤m成立
- 对于任意整数 l , r ( 1 ≤ l ≤ r ≤ n ) l,r(1\\leq l\\leq r\\leq n) l,r(1≤l≤r≤n), a , b a,b a,b在区间的 [ l , r ] [l,r] [l,r]的最左端最大值位置相同
输出满足条件的序列 b b b的数量,对 1 0 9 + 7 10^9+7 109+7取模。
有 t t t组数据。
数据范围
1
≤
t
≤
1
0
3
1\\leq t\\leq 10^3
1≤t≤103
2
≤
n
,
m
≤
1
0
5
,
∑
n
×
m
≤
1
0
6
2\\leq n,m\\leq 10^5,\\sum n\\times m\\leq 10^6
2≤n,m≤105,∑n×m≤106
对于所有
i
(
1
≤
i
≤
n
)
i(1\\leq i\\leq n)
i(1≤i≤n),满足
1
≤
a
i
≤
m
1\\leq a_i\\leq m
1≤ai≤m
题解
首先我们可以想到,对于一个区间 [ l , r ] [l,r] [l,r]和它的最左端最大值位置 x x x,我们可以把这个区间分成 [ l , x − 1 ] [l,x-1] [l,x−1]和 [ x + 1 , r ] [x+1,r] [x+1,r]两个区间来处理。
设 f ( l , r , x , v ) f(l,r,x,v) f(l,r,x,v)表示区间 [ l , r ] [l,r] [l,r]的最左端最大值位置为 x x x且其值小于等于 v v v时这个区间有多少种放法。那么有
f ( l , r , x , v ) = f ( l , r , x , v − 1 ) + f ( l , x − 1 , v l x , v − 1 ) × f ( x + 1 , r , v r x , v ) f(l,r,x,v)=f(l,r,x,v-1)+f(l,x-1,vl_x,v-1)\\times f(x+1,r,vr_x,v) f(l,r,x,v)=f(l,r,x,v−1)+f(l,x−1,vlx,v−1)×f(x+1,r,vrx,v)
因为一个最左端最大值位置只对应一段区间,且一段区间只有一个最左端最大值位置,所以我们可以用 v l x vl_x vlx表示以 x x x为最左端最大值位置的区间 [ l , r ] [l,r] [l,r]中 [ l , x − 1 ] [l,x-1] [l,x−1]的最左端最大值位置, v r x vr_x vrx表示 [ x + 1 , r ] [x+1,r] [x+1,r]的最左端最大值位置。
因为一开始只有一段区间 [ 1 , n ] [1,n] [1,n],而每次加入一个最左端最大值位置只会多算两个区间,所以总共只会有不超过 2 n + 1 2n+1 2n+1个区间,可以 O ( n log n ) O(n\\log n) O(nlogn)将所有 v l x , v r x vl_x,vr_x vlx,vrx计算出来。
然后就是计算 f ( l , r , x , v ) f(l,r,x,v) f(l,r,x,v)了。用记忆化搜索,每个位置只会被计算一次,那么这样的时间复杂度为 O ( n m ) O(nm) O(nm)。
总时间复杂度为 O ( ∑ n × m + n log n ) O(\\sum n\\times m+n\\log n) O(∑n×m+nlogn)。
code
#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
int T,n,m,now,bz,a[200005],v1[200005],v2[200005],tr[1000005],th[1000005];
long long mod=1000000007;
vector<long long>f[200005];
void build(int k,int l,int r)
if(l==r)
tr[k]=a[l];th[k]=l;
return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
if(tr[lc]>=tr[rc])
tr[k]=tr[lc];th[k]=th[lc];
else
tr[k]=tr[rc];th[k]=th[rc];
void find(int k,int l,int r,int x,int y)
if(l>=x&&r<=y)
if(now<tr[k])
now=tr[k];bz=th[k];
return;
int mid=l+r>>1;
if(x<=mid) find(lc,l,mid,x,y);
if(y>mid) find(rc,mid+1,r,x,y);
int pt(int l,int r)
if(l>r) return 0;
now=0;bz=0;
find(1,1,n,l,r);
int x=bz;
v1[x]=pt(l,x-1);v2[x]=pt(x+1,r);
return x;
long long gt(int l,int r,int x,int v)
if(l>r||v==0) return 0;
if(l==r) return v;
if(f[x][0]) return f[x][v];
for(int i=1;i<=m;i++)
long long re=1;
CodeForces 863D Yet Another Array Queries Problem 暴力
题意:长度为 n 的数组 a[] ,有两个操作: 1、区间 [l,r] 的数向右移,即 a[i+1] 变为 a[i],a[l] 变为 a[r] 。 2、反转区间 [l,r] 。 最后有 m 个询问 q,输出最后得到的数组里 a[q] 的值。
tags: 一开始觉得是什么数据结构,发现 m <= 100,这样就直接暴力,对于每个询问从后往前反过来操作一遍。
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi first
#define se second
typedef long long ll;
const int N = 200005;
int n, q, m, a[N], t[N], l[N], r[N];
int main()
{
scanf("%d%d%d", &n, &q, &m);
rep(i,1,n) scanf("%d", &a[i]);
rep(i,1,q) scanf("%d%d%d", &t[i], &l[i], &r[i]);
int bi;
rep(j,1,m)
{
scanf("%d", &bi);
per(i,q,1)
{
if(l[i]<=bi && bi<=r[i])
{
if(t[i]==1)
{
bi = (bi==l[i]) ? r[i] : bi-1;
}
else
{
bi = l[i]+(r[i]-bi);
}
}
}
printf("%d ", a[bi]);
}
return 0;
}
以上是关于CF1748E Yet Another Array Counting Problem的主要内容,如果未能解决你的问题,请参考以下文章
CF-1359 D. Yet Another Yet Another Task ST表+单调队列