1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營 G.Greater and Greater

2020牛客暑期多校訓練營 G.Greater and Greater

  • 題意

    • 給出兩個序列 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;
      }