2020牛客暑期多校训练营(第二场)G Greater and Greater 题解
题意:
给一个长为n的序列A,一个长为m的序列B,要求计算有多少个i(1<=i<=n-m+1),使得A[i+j-1]>=B[j](1<=j<=m)
当时第一反应是魔改KMP,用next数组求答案,然后各种魔改各种WA,遂放弃。
我们考虑利用bitset求解。
我们先求出长为m的bitset F[i],F[i][j]表示A[i]是否大于等于B[j],显然,本质不同的F[i]只有m种。
所以求我们不必直接求F数组,而是先求出本质不同的那m种情况的bitset,需要用F[i]时直接二分就可以了。
可以发现,如果 i 满足A[i+j-1]>=B[j](1<=j<=m),则F[i][1]=1,F[i+1][2]=1,F[i+2][3]=1……
因此,我们设长度为m的滚动bitset ans,每次ans右移一位,与上A[i],此时ans[0]为F[i][1]&F[i+1][2]&F[i+2][3]……,若ans[0]为1则说明i可行。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<bitset> 8 #define N 150005 9 #define M 50005 10 using namespace std; 11 int n,m,A[N],B[N]; 12 struct no{ 13 int val,id; 14 }node[N]; 15 bool cmp(no a,no b) 16 { 17 if(a.val==b.val)return a.id<b.id; 18 return a.val<b.val; 19 } 20 bitset<M> S[M],ans; 21 int find(int x) 22 { 23 if(x<node[1].val)return 0; 24 if(x>node[m].val)return m; 25 int li=1,ri=m,mid,ans=-1; 26 while(li<=ri) 27 { 28 mid=(li+ri)>>1; 29 if(node[mid].val<=x) li=mid+1,ans=mid; 30 else ri=mid-1; 31 } 32 return ans; 33 } 34 int main() 35 { 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=n;i++) 38 { 39 scanf("%d",&A[i]); 40 } 41 for(int i=1;i<=m;i++) 42 { 43 scanf("%d",&B[i]); 44 node[i].val=B[i]; 45 node[i].id=i; 46 } 47 sort(node+1,node+m+1,cmp); 48 for(int i=1;i<=m;i++) 49 { 50 S[i]=S[i-1]; 51 S[i].set(node[i].id-1); 52 } 53 for(int i=n;i>n-m+1;i--) 54 { 55 int op=find(A[i]); 56 ans>>=1; 57 ans.set(m-1); 58 ans&=S[op]; 59 } 60 int sum=0; 61 // cout<<endl; 62 for(int i=n-m+1;i;i--) 63 { 64 int op=find(A[i]); 65 // cout<<i<<endl; 66 67 ans>>=1; 68 // for(int j=0;j<m;j++) cout<<ans[j]<<' '; 69 // cout<<endl; 70 ans.set(m-1); 71 ans&=S[op]; 72 // cout<<i<<endl; 73 sum+=ans[0]; 74 } 75 printf("%d\n",sum); 76 return 0; 77 }