2020牛客暑期多校训练营(第二场)G. Greater and Greater
https://ac.nowcoder.com/acm/contest/5667/G
题目描述:给长为n的数组a,和长为m的数组b。问a中有多少个长为m的连续的子数组s满足:s[i]>=b[i],i∈[1,m]。
官方题解如上,接下来结合我的理解解释一下:
题解的s数组不难理解,s[i][j]=1就表示a[i]>=b[j],j∈[1,m]。s[i]就是对于a[i]来说,是否满足a[i]这个数>=b数组中的数。
假设把b数组排序后,对一个数a[i],a[i]按大小插入b数组,那么a[i]前面的都小于a[i],也就是把对应在s[i]的位置设为1,a[i]后面的数都大于a[i],所以设为0。因此,s[i]只有m种,取决于a[i]所在排序后b数组的位置。
而cur数组是设置的最为巧妙地,
对cur[i]来说,把他地关系列出来:
cur[i][m]= a[i]>=b[m]
cur[i][m-1]= (a[i]>=b[m-1]) && (a[i+1]>=b[m])
cur[i][m-2]= (a[i]>=b[m-2]) && (a[i+1]>=b[m-1]) && (a[i+2]>=b[m])
.......依次下去
可以看出cur[i][j]就是 a[i]、a[i+1]...a[i+m-j]分别>=b[j]、b[j+1]...b[m]。
cur[i+1][m]= a[i+1]>=b[m]
cur[i+1][m-1]= (a[i+1]>=b[m-1]) && (a[i+2]>=b[m])
和上面的cur[i]放在一起:
cur[i][m-1]= (a[i]>=b[m-1]) && (a[i+1]>=b[m])
cur[i][m-2]= (a[i]>=b[m-2]) && (a[i+1]>=b[m-1]) && (a[i+2]>=b[m])
很容易就想到cur[i]=cur[i+1]移位,在和a[i]对应的s数组做&运算。
注意bitset是从高位开始存储:m、m-1......1。
所以cur[i]=((cur[i+1]>>1)|Im)& s[i]。
代码:
#include<cstdio> #include<iostream> #include<deque> #include<cstring> #include<cmath> #include<map> #include<vector> #include<stack> #include<algorithm> #include<queue> #include<set> #include<bits/stdc++.h> #define cfast ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define sf(x) scanf("%lf",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define all(a) a.begin(),a.end() #define range(a,x,y) a+x,a+y+x #define dbug printf("bbbk\n") using namespace std; using namespace __gnu_cxx; typedef long long ll; typedef unsigned long long ull; typedef long double ld; typedef pair<ll,ll> P; const int N=2e5+9; const int MN=4e4+9; const ll mod=998244353; const int MAX=1e9; const ll base=1331; const ll INF=1e15+7; int a[N],b[N],pos[N]; bitset<MN> s[MN],cur,I; bool cmp(int x,int y){ return b[x]<b[y]; } int main() { //freopen("t.txt","r",stdin); cfast; int n,m;cin>>n>>m; fu(i,1,n) cin>>a[i]; fu(i,1,m) cin>>b[i],pos[i]=i; sort(pos+1,pos+m+1,cmp); fu(i,1,m) s[i]=s[i-1],s[i][pos[i]]=1; I[m]=1; int ans=0; sort(b+1,b+m+1); //bitset<4> ss;ss[3]=1; //cout<<"tmp: "<<ss<<" "<<(ss<<1)<<endl; fd(i,n,1){ int p=upper_bound(b+1,b+m+1,a[i])-b-1;//找到在>=b中的最小位置 //bitset是从高位存储,m、m-1、m-2......1 //cur[i][j]表示从a[i]开始, //a[i]、a[i+1]...a[i+m-j]分别>=b[j]、b[j+1]...b[m]。 //也就是从i开始的后缀一一匹配 //再观察cur[i]和cur[i+1]的关系,就不难得出下式 cur=(((cur>>1)|I)&s[p]); if(cur[1]==1) ans++; } cout<<ans<<endl; return 0; }