题目链接:Problem - 1779D - Codeforces
input:
7
3
3 3 3
2 1 2
2
1 2
6
3 4 4 6 3 4
3 1 2 3 2 3
3
3 2 3
10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
10
1 2 3 4 5 6 7 8 9 10
3
1 1 1
1 1 2
12
4 2 4 3 1 5 6 3 5 6 2 1
13
7 9 4 5 3 3 3 6 8 10 3 2 5
5 3 1 5 3 2 2 5 8 5 1 1 5
8
1 5 3 5 4 2 3 1
13
7 9 4 5 3 3 3 6 8 10 3 2 5
5 3 1 5 3 2 2 5 8 5 1 1 5
7
1 5 3 4 2 3 1
3
19747843 2736467 938578397
2039844 2039844 2039844
1
2039844
otuput:
YES
NO
YES
NO
YES
NO
YES
题意:
Boris 想理发,其头发可视为大小为 n 的数组 ,每根头发的长度为 ai ,Boris 对于每根头发的理想长度为 bi 。理发师有 m 把剪刀,对于长度为 x 的剪刀,每把剪刀至多可以使用一次(可能存在若干把剪刀长度相同)。
对于每一把长度为 x 剪刀的使用,理发师可以选择任意 l,r,使得 a[l , r] 的所有 ai 变为 min(ai , x)
问在上述规则下,Boris 的所有头发是否都可以达到理想情况。
思路:
首先我们可以知道,不满足条件的情况有两种:
1.存在 i ,使得 ai < bi
2.存在 x ,长度为 x 的剪刀的数量小于需要使用的数量
第一种情况可以直接处理,第二种情况则需要我们通过处理数据来判断。
实际上 ai 只对处理第一种情况,和判断当前头发是否需要修剪有意义,所以可以放一边不看,重点看 bi。
首先最朴素的修剪方法一定是每根头发配备一把对应理想长度的剪刀,所以我们先处理出来每种长度的头发出现的位置。随后如果我们想将两根理想长度相同的头发同时修剪,需要考虑这两根头发之间是否存在比当前目标长度长的头发,若不存在,则可以合并修剪,否则不合法。对于可以合并修剪的部分,我们将先前存的需要剪刀的数量减一(区间查询最大值有多种方案,这里我使用了树状数组,当然线段树亦可)。
遍历处理后,对于每种长度需要的剪刀数量,判断是否大于拥有的剪刀数量即可。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define endl "\n"
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
int t,n,m;
int a[N],b[N];
int h[N];
int lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
int lowx,k;
while(x<=n)
{
h[x]=b[x];
lowx=lowbit(x);
for(k=1;k<lowx;k<<=1)
{
h[x]=max(h[x],h[x-k]);
}
x+=lowbit(x);
}
}
int query(int x,int y)
{
int ans=0;
while(y>=x)
{
ans=max(b[y],ans);
y--;
for(;y-lowbit(y)>=x;y-=lowbit(y))
{
ans=max(h[y],ans);
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
map<int,int> mp;
map<int,vector<int> > mp1;
map<int,int> mp2;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
if(a[i]!=b[i])
{
mp1[b[i]].pb(i);
}
update(i);
}
cin>>m;
int k;
for(int i=1;i<=m;i++)
{
cin>>k;
++mp[k];
}
bool f=1;
for(int i=1;i<=n;i++)
{
if(a[i]<b[i])
{
f=0;
break;
}
if(a[i]!=b[i])
++mp2[b[i]];
}
for(auto x:mp1)
{
int l=0,r=1;
while(l<x.second.size()&&r<x.second.size())
{
if(query(x.second[l]+1,x.second[r]-1)<=x.first)
{
++r;
--mp2[x.first];
}
else
{
l=r;
++r;
}
}
}
for(auto x:mp2)
{
if(x.second>mp[x.first])
{
f=0;
break;
}
}
if(f)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}