BZOJ4810: [Ynoi2017]由乃的玉米田

BZOJ4810

巧妙地利用bitset
QAQ 可能只是我弱沒看出來。
莫隊還是很容易看出來的。
然後就是統計一下每一個值出現的個數。用cnt 數組記錄。
對於操作3乘法而言,直接枚舉因數,暴力判斷一下就可以了。
用一個bitsetf 記錄每個值是否出現過。
那麼對於操作1減法來說,就直接將f 左移x 位,然後且上原集f ,判斷是否有交就可以了。這個應該還比較好理解。相當於就是尋找是否存在差爲x 的兩個值嘛。
然而對於操作2加法來說,求和就不能一個bitset 解決了。
差值好求,和不好求,那麼考慮將求和轉爲求差。那麼記錄一個最大值Mx
每次求ai+aj=x 可以轉化爲ai=(Mxaj)+xMx
如此,就可以維護一個倒着的,bitsetg ,如,加入值ai ,那麼fai=1 ,gMxai=1 ,每次將g 左移xMxf 求且,或者f 左移Mxx 位與g 求且就可以了。而且題目還說了同一個位子可以取兩次。QAQ真和善。

【代碼】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <bitset>
#define N 100005
#define mod 1000000007
#define INF 0x7fffffff
using namespace std;
typedef long long ll;

ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,block,Mx,L,R;
int a[N],cnt[N],bl[N],ans[N];
bitset<N>f,g,h; 

class Query{
    public:
        int f,l,r,x,id;
    Query(){}
    Query(int ff,int ll,int rr,int xx,int ii) {
        f=ff,l=ll,r=rr,x=xx,id=ii;
    }   
}Q[N];

bool operator <(Query a,Query b){
    return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);
}

void Add(int x)
{
    cnt[x]++;
    if(cnt[x]==1) f[x]=1,g[Mx-x]=1;
}

void Delete(int x)
{
    cnt[x]--;
    if(!cnt[x]) f[x]=0,g[Mx-x]=0;
}

int Solve_Minus(int x){
    return ((f<<x)&f).count()!=0?1:0;
}

int Solve_Plus(int x){
    return ((f<<(Mx-x))&g).count()!=0?1:0;
}

int Solve_Multi(int x){
    for(int i=1;i*i<=x;i++) if(x%i==0) {
        if(cnt[i]&&cnt[x/i]) return 1;
    }   
    return 0;
}

void Get_Ans(int x)
{
    if(Q[x].f==1) ans[Q[x].id]=Solve_Minus(Q[x].x);
    else if(Q[x].f==2) ans[Q[x].id]=Solve_Plus(Q[x].x);
    else ans[Q[x].id]=Solve_Multi(Q[x].x);
}

int main()
{
    n=read(),m=read();block=(int)sqrt(n);Mx=N-1;
    for(int i=1;i<=n;i++) a[i]=read(),bl[i]=(i-1)/block+1;
    for(int i=1;i<=m;i++) 
        Q[i].f=read(),Q[i].l=read(),Q[i].r=read(),Q[i].x=read(),Q[i].id=i;
    sort(Q+1,Q+1+m);
    for(int i=Q[1].l;i<=Q[1].r;i++) Add(a[i]);
    Get_Ans(1);
    L=Q[1].l,R=Q[1].r;
    for(int i=2;i<=m;i++)
    {
        while(L<Q[i].l) Delete(a[L++]);
        while(R<Q[i].r) Add(a[++R]);
        while(L>Q[i].l) Add(a[--L]);
        while(R>Q[i].r) Delete(a[R--]);
        Get_Ans(i);
    }
    for(int i=1;i<=m;i++) printf(ans[i]?"yuno\n":"yumi\n");
    return 0;
}
發佈了212 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章