题目传送门
题意: 给你一个长度为n的数组a,一个长度为m的数组b,问你A中有多少个子数组S,满足S[i]>=b[i],i∈{1,2,3,…m}。
思路: 开两个bitset,ans表示数组a中的哪些位置可能可以作为开头,temp表示原数组a中哪些位置可以匹配到当前的b[i]。我们先对a和b数组记录位置并分别排序,这样temp就可以一直沿用,因为排序之后大于b[i].first的肯定大于b[i+1].first。每次更新完temp之后,大于b[i].first的就找出来了。找到之后,比如原数组中第k个元素可以匹配当前b[i].fi,temp中第k位是等于1的,我们将temp右移(b[i].second-1)位,就表示原数组a中第(k-b[i].se-1)可能作为开头,把排序后的b数组遍历完成之后,就得到了最后的ans,这时候ans中的1就是完全合法的了。输出1的个数就行。
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
//#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-7;
const double PI=acos(-1);
pii a[N],b[N];
bitset<N>ans,temp;
bool cmp(pii a,pii b)
{
return a.fi>b.fi;
}
signed main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i].fi;
a[i].se=i;
}
for(int i=1;i<=m;i++)
{
cin>>b[i].fi;
b[i].se=i;
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+m+1,cmp);
ans.set();
temp.reset();
for(int i=1,j=1;i<=m;i++)
{
while(j<=n&&a[j].fi>=b[i].fi)
temp.set(a[j++].se);
ans&=(temp>>(b[i].se-1));
}
cout<<ans.count()<<endl;
}