小清新人渣的本願(莫隊+bitset)

小清新人渣的本願

這兩天寫了些bitsetbitset的題,但都不想寫題解。。。正巧這道題還結合了莫隊,也是正在學習的,就記錄一下吧。

題意:

給定一個aa數組,有三種詢問:

  1. 詢問[l,r][l,r]區間中是否有差爲xx的數對;
  2. 詢問[l,r][l,r]區間中是否有和爲xx的數對;
  3. 詢問[l,r][l,r]區間中是否有積爲xx的數對。

思路:

  1. 先只考慮三種詢問後面的部分,不考慮區間問題。
  2. 要求是否存在差爲xx的數對,顯然只需要知道每個數向前(或向後)xx的數值是否存在,要檢索所有數字的話,考慮使用bitsetbitset(b(b&bb<<x).anyx).any()就可以知道是否存在啦!
  3. 要求是否存在和爲xx的數對,有一個小技巧,同時維護一個反轉的bitsetbitset,想想將反轉的bitsetbitset向右移動NNaa數組的值域)位,肯定這個bitsetbitset就全爲00了;但如果少移動xx個位置的話,就相當於把原狀態中前[0,x][0,x]的部分保留了,並且是反轉的;顯然將原bitsetbitset和這個經過處理的bitsetbitset取與,就可以知道是否有和爲xx的數對啦!
  4. 而積爲xx是否存在反而最簡單,考慮這個小問題的複雜度,mm(1e5)(≤1e5)個詢問,xx又是小於1e51e5的,因此枚舉xx所有較小因數的複雜度爲O(mx)O(m*\sqrt{x}),完全是可以接受的!
  5. 至此,此問題就只剩維護區間狀態的問題了;上述三種問題都指向了一種狀態——某個數字是否存在,這恰好是莫隊的常見問題,不難想出。因此,總複雜度爲莫隊的端點移動*每個詢問的答案判斷,爲O(n32(n+n32))O(n^\frac{3}{2}*(\sqrt{n}+\frac{n}{32}))(其中mmaa的值域都用nn代替了),感覺還是能被卡住的。

代碼

#include "bits/stdc++.h"
#define hhh printf("hhh\n")
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}

const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-7;
const int N = 100001;

int n, m, len;
int a[maxn], cnt[maxn], ans[maxn];
bitset<N+1> b1, b2;

struct P{
    int opt, l, r, x, id;
    friend bool operator < (const P &a, const P &b) {
        if((a.l-1)/len!=(b.l-1)/len) return a.l<b.l;
        if((a.l-1)/len%2) return a.r>b.r;
        return a.r<b.r;
    }
}p[maxn];

inline void del(int x) {
    if(--cnt[x]==0) b1[x]=0, b2[N-x]=0;
}
inline void add(int x) {
    if(cnt[x]++==0) b1[x]=1, b2[N-x]=1;
}

int main() {
    //ios::sync_with_stdio(false); cin.tie(0);
    n=read(), m=read();
    for(int i=1; i<=n; ++i) a[i]=read();
    for(int i=1; i<=m; ++i) {
        int opt=read(), l=read(), r=read(), x=read();
        p[i]=(P){opt,l,r,x,i};
    }
    len=sqrt(m);
    sort(p+1,p+1+m);
    int l=1, r=0;
    for(int i=1; i<=m; ++i) {
        while(l<p[i].l) del(a[l++]);
        while(l>p[i].l) add(a[--l]);
        while(r<p[i].r) add(a[++r]);
        while(r>p[i].r) del(a[r--]);
        if(p[i].opt==1) ans[p[i].id]=(b1&b1<<p[i].x).any()?1:0;
        else if(p[i].opt==2) ans[p[i].id]=(b1&b2>>(N-p[i].x)).any()?1:0;
        else {
            bool f=0;
            for(int j=1; j*j<=p[i].x; ++j) {
                if(p[i].x%j==0&&b1[j]&&b1[p[i].x/j]) { f=1; break; }
            }
            ans[p[i].id]=f;
        }
    }
    for(int i=1; i<=m; ++i) {
        if(ans[i]) printf("hana\n");
        else printf("bi\n");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章