2020牛客暑期多校訓練營 G.Greater and Greater
阿新 • • 發佈:2020-07-14
-
題意
- 給出兩個序列 A、B,其長度分別為 n、m,保證 $n>m $ ,求 A 中有多少個長度為 m 的子串 S,使得\(\forall i\in\{1,2,\cdots,m\},S_i \ge B_i\)
-
解析
-
出題人直播時表示看到資料很容易想到用 \(bitset\) (霧
-
對於每一個 \(A_i\) 需要求一個長度為 \(m\) 的 \(bitset\) \(S_i\) ,其中 \(S_i[j] = 1\) 表示 $A_i \ge B_j $ 。
-
那麼如果得到了所有的 \(S_i\) 該如何判斷答案呢
-
可以發現只有某一列的三個數全為 1 ,才對答案有貢獻。做法下面等會講。
-
現在我們要考慮的問題就是如何高效地得到所有地 \(S_i\) 。
-
發現,在對 \(B\) 序列排序後,如果求出 \(B\) 對應的 \(bitset\) \(S_j^‘\),會發現 \(i\) 位置的 \(bitset\) 和 \(i-1\) 的 \(bitset\) 相比,只在第 \(i\) 大的數的對應位置上多了一個 1。
-
我們現在對 \(B\) 也進行一次 \(bitset\) 操作,那麼如果 \(A[i]\) 值在 \([B[j],B[j+1])\) ,那麼可以求出 \(S_i = S_j^‘\)
-
那麼現在要求 \(S_i\) 只需要二分找到 \(A[i]\) 在 \(B\)
-
在解決了 \(S_i\) 後要考慮如何得到答案,我們發現 \(S_i\) 和 \(S_{i-1}\) 相比,只需要將 \(S_{i-1}\) 右移一位再進行 與 操作,就能把兩者相聯絡起來,那麼我們只要維護一個從起始開始的 與 的和 \(ans\),如果 \(ans[0] = 1\) 那麼就對答案有貢獻。
-
注意要先處理好 \(A\) 中前 \(m-1\) 項,而且在 \(ans\) 的每次右移過程中需要將 \(ans[m-1]\) 賦值為 1。不然會影響到之後的判斷。
-
-
程式碼
-
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int Maxb = 10; const int Maxa = 2e5+10; const int Inf = 0x7f7f7f7f; const int Mod = 1e9+7; vector<pii> v; int a[Maxa],b[Maxb]; bitset<Maxb> Bit[Maxb]; int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); v.push_back(make_pair(0,0)); for(int i=1;i<=m;i++) { scanf("%d",b+i); v.push_back(make_pair(b[i],i)); } sort(v.begin(),v.end()); for(int i=1;i<=m;i++) { Bit[i] = Bit[i-1]; Bit[i].set(m - v[i].second,1); } bitset<Maxb> ans; for(int i=1;i<m;i++) { pii cnt; cnt = make_pair(a[i],m+1); int t = lower_bound(v.begin(),v.end(),cnt) - v.begin() - 1; ans >>= 1; ans.set(m-1,1); ans &= Bit[t]; } int Ans = 0; for(int i=m;i<=n;i++) { pii cnt; cnt = make_pair(a[i],m+1); int t = lower_bound(v.begin(),v.end(),cnt) - v.begin() - 1; ans >>= 1; ans.set(m-1,1); ans &= Bit[t]; Ans += ans[0]; } cout<<Ans<<endl; return 0; }
-