牛客多校二--J题 farm

题目链接

题意:给出一个n*m的矩阵,矩阵上每个点有一种植物,有T次操作,对于每次操作给出两个殿P1,P2,v,要求给以P1为左上角以P2为右下角的子矩阵中每个植物施种类为v的化肥,如果化肥种类和植物种类不一样,这该点的植物会立马死亡,求T次操作结束之后死亡的植物数量。

这题比赛时没想到解题方法,赛后看题解大概有三种解法:

​    一:二维树状数组

​    二:线段树+扫瞄线

​    三:随机化算法

这里先给出我觉得的最玄学的随机化算法,前两种写法后续更新。

由于题目中n*m<=1e6,种类<=1e6,所以对于每个种类可以给它随机化一个[1e6,1e7]的权值b[i],然后修改操作便是给对应区间加上要施的肥料种类对应的随机化值,最后计算出每个点最后总的改变值cnt(i,j),如果cnt(i,j)%b(a(i,j))!=0,则该点的植物有极大的可能是死亡的。对于每个格子,如果权值为p,则该点这种做法的正确率为(p-1)/p。

这题没有给出n和m的具体范围,所以只能用vector了。

/*************************************************************************
    > File Name: nkdx2-J.cpp
    > Author: cyh
    > Mail: 
    > Created Time: 2018年07月22日 星期日 18时44分42秒
 ************************************************************************/

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll tree[rt].l
#define rr tree[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=1e6+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int n,m,t;
vector<LL> b,cnt[maxn];
vector<int> a[maxn];
LL Rand(){return (1ll*rand()<<15)+rand();}
int main()
{ 
    scanf("%d%d%d",&n,&m,&t);
    srand(233);
    b.push_back(0ll);
    for(int i=1;i<=n*m;i++) b.push_back(0ll),b[i]=Rand();
    for(int i=0;i<=n+1;i++){
        for(int j=0;j<=m+1;j++){
            a[i].push_back(0);
            cnt[i].push_back(0ll);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
           scanf("%d",&a[i][j]);
        }
    }
    int x1,y1,x2,y2,c;
    for(int i=1;i<=t;i++){
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
        cnt[x1][y1]+=b[c];
        cnt[x2+1][y2+1]+=b[c];
        cnt[x2+1][y1]-=b[c];
        cnt[x1][y2+1]-=b[c];
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cnt[i][j]+=cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1];
            if(cnt[i][j]%(b[a[i][j]])) ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

更新~~~~~~~~~~

此题另一种解法,对于每一个数,数据范围为[1,1e6],二进制最多20位,所以我们可以看每个数每一位的变化,复杂度大概1e7,因为对于每个数如果后来变成了不同的数,至少有一个二进制位与原来的数不同。其实这两种解法的更新部分都与二维树状数组类似。

AC代码:

/*************************************************************************
    > File Name: nkdx2-J题2.cpp
    > Author: cyh
    > Mail: 
    > Created Time: 2018年07月23日 星期一 09时03分54秒
 ************************************************************************/

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll tree[rt].l
#define rr tree[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=2e6+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int a[maxn],cnt[maxn][2],vis[maxn];
int n,m,T;
inline int f(int x,int y){return x*m+y;}
struct node{int x1,y1,x2,y2,c;}Q[maxn];
int main()
{ 
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
        scanf("%d",&a[f(i,j)]);
    }
    for(int i=1;i<=T;i++) scanf("%d%d%d%d%d",&Q[i].x1,&Q[i].y1,&Q[i].x2,&Q[i].y2,&Q[i].c);
    int ans=0;
    for(int v=0;v<=20;v++){
        for(int i=1;i<=T;i++){
            int x1=Q[i].x1,y1=Q[i].y1,x2=Q[i].x2,y2=Q[i].y2,c=Q[i].c;
            cnt[f(x1,y1)][(c>>v)&1]++;
            cnt[f(x2+1,y2+1)][(c>>v)&1]++;
            cnt[f(x1,y2+1)][(c>>v)&1]--;
            cnt[f(x2+1,y1)][(c>>v)&1]--;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cnt[f(i,j)][0]+=cnt[f(i-1,j)][0]+cnt[f(i,j-1)][0]-cnt[f(i-1,j-1)][0];
                cnt[f(i,j)][1]+=cnt[f(i-1,j)][1]+cnt[f(i,j-1)][1]-cnt[f(i-1,j-1)][1];
                if(!vis[f(i,j)]&&cnt[f(i,j)][((a[f(i,j)]>>v)&1)^1]) ans++,vis[f(i,j)]=1;
            }
        }
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt[f(i,j)][0]=cnt[f(i,j)][1]=0;
    } 
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37171272/article/details/81210485