[Ynoi2017] 由乃的玉米田

题目链接 : [Ynoi2017] 由乃的玉米田

弱化版 : 小清新人渣的本愿

这两道题都是看会不会用bitset,bitset大胜利

  1. 减操作 : 用一个bitset \(vis1\) 记录一个数是否出现,如果有就是\((vis1\And(vis>>x)).count()\ge 1\),其实就是看是否有数\(a\)和数\(a+x\)同时出现

  2. 加操作 : 同减操作,但是要转化一下,就是\(a+b=x\Leftrightarrow a-(100000-b)=x-100000\)。记录一个相反的bitset \(vis2\),然后就是判断是否 \((vis1\And(vis2>>(100000-x))).count()\ge 1\)(因为vis2是相反的bitset,所以不是右移\(x-100000\)位而是\(100000-x\)位)

  3. 乘操作 : \(O(\sqrt x)\)暴力跑即可

  4. 除操作 : 根号分治

    1. \(x\ge \sqrt{100000}\)的暴力跑,复杂度是正确的\(O(\sqrt{n})\)
    2. 对于\(x< \sqrt{100000}\)的,将其特殊处理

    定义两个数组 : \(pre_x\)表示\(x\)上一次(包括当前位置,因为一个位置可以重复选两次)出现的位置,\(lastpos_i\)表示到\(i\)时最后一个合法点对\((i,j)(i\le j)\)\(i\)的位置。

    然后将所有\(op = 4 \And x<\sqrt{100000}\)的单独记录出来,单独处理。

    枚举\(x\),然后用一个指针\(i\; O(n)\)扫一遍\(a\),假设当前扫到的位置为\(i\),记录当前最后一个合法点对\((i,j)\)\(i\)的位置为\(res\),依次执行以下操作 :

    1. \(i\)替换\(pre_{a_i}\)
    2. 如果\(a_i\times x\le 100000\),那么\(res = \max(res,pre_{a_i\times x})\)
    3. 如果\(a_i\bmod x = 0\),那么\(res = \max(res,pre_{\frac{a_i}{x}})\)

    最后统计一下答案,就是比较\(l\)\(lastpos_r\)的大小关系,如果\(l>lastpos_r\)则无解。

预处理的复杂度是\(O(n\sqrt n)\),莫队的复杂度是\(O(n(\sqrt{n} + \frac{n}{w}))\)的,可以通过,无需卡常

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    // FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10,M = 330;
int n,m,a[N],L[M],R[M],pos[N],len,ct[N];
struct node{int op,l,r,x,id;}q[N];int cnt = 0;
bool ans[N];
struct Node{int l,r,id;};
vector<Node> p[M];
int pre[N],lastpos[N];
inline void solve(){
    cin>>n>>m;
    for(int i = 1;i <= n; ++i) cin>>a[i];
    for(int i = 1,op,l,r,x;i <= m; ++i){
        cin>>op>>l>>r>>x;
        if(op == 4 && x < M) p[x].emplace_back((Node){l,r,i});
        else q[++cnt] = {op,l,r,x,i};
    }
    for(auto i:p[1]) ans[i.id] = true;
    for(int now = 2;now < M; ++now){
        if(p[now].empty()) continue;
        int res = 0;
        memset(lastpos,0,sizeof lastpos);
        memset(pre,0,sizeof pre);
        for(int i = 1;i <= n; ++i){
            int y = a[i];
            pre[y] = i;
            if(now * y <= 100000) res = max(res,pre[now*y]);
            if(y % now == 0) res = max(res,pre[y/now]);
            lastpos[i] = res;
        }
        for(auto i : p[now]) ans[i.id] = (i.l <= lastpos[i.r]);
    }

    len = sqrt(n);
    for(int i = 1;i <= len; ++i) L[i] = R[i - 1] + 1,R[i] = i * len;
    if(R[len] < n) len ++, L[len] = R[len - 1] + 1,R[len] = n;
    for(int i = 1;i <= len; ++i) for(int j = L[i];j <= R[i]; ++j) pos[j] = i;
    sort(q+1,q+1+cnt,[](node x,node y){return (pos[x.l]==pos[y.l]?(pos[x.l]&1?x.r<y.r:x.r>y.r):x.l<y.l);});

    bitset<N> vis1,vis2;
    int left = 1,right = 0;
    auto add = [&](int x) -> void{
        if(!ct[x])vis1[x] = vis2[100000 - x] = true;
        ct[x]++;
    };
    auto del = [&](int x) -> void{
        ct[x]--;
        if(!ct[x]) vis1[x] = vis2[100000 - x] = false;
    };
    for(int i = 1;i <= cnt; ++i){
        int l = q[i].l,r = q[i].r,op = q[i].op,x = q[i].x;
        while(left > l) add(a[--left]);
        while(right < r) add(a[++right]);
        while(left < l) del(a[left++]);
        while(right > r) del(a[right--]);
        if(op == 1) ans[q[i].id] = (vis1&(vis1>>x)).count();
        if(op == 2) ans[q[i].id] = (vis1&(vis2>>(100000-x))).count();
        if(op == 3){
            int k = sqrt(x);
            for(int j = 1;j <= k; ++j){
                if(x % j == 0 && vis1[j] && vis1[x/j]){ans[q[i].id] = true;break;}
            }
        }
        if(op == 4){
            for(int j = 1;j <= 100000/x; ++j) if(vis1[j] && vis1[j*x]){ans[q[i].id] = true;break;}
        }
    }
    for(int i = 1;i <= m; ++i) cout<<(ans[i]?"yuno\n":"yumi\n");
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    solve();   
}
posted @ 2024-08-23 16:24  CuFeO4  阅读(25)  评论(1编辑  收藏  举报