2018牛客多校2 – J farm 随机乱搞/二进制分组

题意:给定n*m的格子,每个格子有不同的种类,q次操作,每次操作使[x1,y1]到[x2,y2]的格子除了k类型的以外都删除,最后单次询问所有格子被删了几个

官方题解提到了两种有意思的做法,随机和二进制分组

目前我写了随机的做法,简单粗暴好懂

(upd.劳资总算把二进制分组的给做出来了!

给每种类型打个随机权值,操作覆盖到的区间都加上这个权值

最后查询的时候只需这道这个点的值是不是该类型的权值的倍数就行了

就这么简单

实现上只需套路作差取前缀和就能得到单点的值,总复杂度$O(n)$

(WA了几发忘记递推前缀了...)

另外提一下二进制分组的思路

对于每个操作的整体而不考虑细节来说,

普通的是更新$O(1)$,针对特定的一组

要比较的是$O(n)$,对应于除了该类型外的其他所有组

那么二进制分组就把各个类型按二进制归类,如果某一位是1就把它归类到某一组,总共$log_2n$组

要比较是否有别的数打到这个格子上,那么必然在二进制的某一位上存在差异

因此可以更新$O(logn)$

查询也是$O(logn)$

具体说明:

搞个特例,种类只有0和1,那么对于1而言0的个数只要大于0就不可以,0而言只要1的个数大于0则不可以

扩展到1e6种,把各个类型分拆成二进制后就是20个0和1的组合,分别维护40个前缀和就可以了

注意第二种方法在实现上不要用vector,不然会各种姿势爆内存

用数组记得保证不越界

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define erep(i,u) for(int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int MAXN = 1e5+11;
const int MAXM = 2e6+11;
const int MOD = 1e9+7;
typedef long long ll;
unsigned int xjb=2333333;
int Rand(){
    return (xjb=xjb*12345+23333)%MOD+1;
}
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
vector<vector<ll> > G,type,pre;
vector<ll> vec;
int main(){
    int n,m,op;
    while(cin>>n>>m>>op){
        G.clear();type.clear();vec.clear();pre.clear();
        G.resize(n+3);type.resize(n+3);pre.resize(n+3);
        rep(i,0,n+2){
            G[i].resize(m+3);
            type[i].resize(m+3);
            pre[i].resize(m+3);
        }
        rep(i,1,n) rep(j,1,m) type[i][j]=read();
        vec.push_back(Rand());
        rep(i,1,n)rep(j,1,m) vec.push_back(Rand());
        rep(i,1,op){
            int x_1=read();
            int y_1=read();
            int x_2=read();
            int y_2=read();
            int k=read();
            G[x_1][y_1]+=vec[k];
            G[x_2+1][y_1]-=vec[k];
            G[x_1][y_2+1]-=vec[k];
            G[x_2+1][y_2+1]+=vec[k];
        }
        ll val=0,cnt=0;
        rep(i,1,n) rep(j,1,m){
            pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+G[i][j];
            if(pre[i][j]%vec[type[i][j]]!=0) cnt++;
        }
        println(cnt);
    }
    return 0;
}
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define erep(i,u) for(int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int MAXN = 1e6+11;
const int MAXM = 2e6+11;
const int MOD = 1e9+7;
typedef long long ll;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int G[21][2][MAXN],type[MAXN],sum[2][MAXN];
bool gg[MAXN];
int n,m,op;
int id(int r,int c){
    if(r<1||c<1) return 0;
    return (r-1)*m+c;
}
int main(){
    while(cin>>n>>m>>op){
        memset(G,0,sizeof G);
        memset(sum,0,sizeof sum);
        memset(gg,0,sizeof gg);
        rep(i,1,n) rep(j,1,m) type[id(i,j)]=read();
        rep(i,1,op){
            int x_1=read();
            int y_1=read();
            int x_2=read();
            int y_2=read();
            int k=read();
            rep(j,0,20){
                bool pos=k>>j&1;
                G[j][pos][id(x_1,y_1)]++;
                if(x_2<n)G[j][pos][id(x_2+1,y_1)]--; //limited
                if(y_2<m)G[j][pos][id(x_1,y_2+1)]--;
                if(x_2<n&&y_2<m)G[j][pos][id(x_2+1,y_2+1)]++;
            }
        }
        int cnt=0;
        rep(k,0,20) rep(i,1,n) rep(j,1,m){
                sum[0][id(i,j)]=sum[0][id(i-1,j)]+sum[0][id(i,j-1)]-sum[0][id(i-1,j-1)]+G[k][0][id(i,j)];
                sum[1][id(i,j)]=sum[1][id(i-1,j)]+sum[1][id(i,j-1)]-sum[1][id(i-1,j-1)]+G[k][1][id(i,j)];
                bool pos=type[id(i,j)]>>k&1;
                if(sum[!pos][id(i,j)]>0) gg[id(i,j)]=1;
        }
        rep(i,1,n) rep(j,1,m) cnt+=gg[id(i,j)];
        println(cnt);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注