牛客-farm(随机化+前缀和定义差分)

https://ac.nowcoder.com/acm/problem/16637

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const int maxn=1e6+2;
const int mod=1e9+7;
typedef long long ll;

//思路:我们重新给每种化肥安排序号,尽可能的不让其之间有倍数的关系,这样的话,q次施肥之后如果当前位置的所有肥料之和是当前植物序号(也就是我们重新分配的序号)的倍数,那么当前植物不会死亡。 

//本题思路: 写一个random的hash,表达里边数唯一。
//给区域加编号k的化肥操作:是让该区域都加上hash[k] 
//若编号k植物格子,查询到值为hash[k]的整数倍,那么说明这格子,只有第k种化肥施加过,如不是,则有其他化肥,那么该植物死亡,ans++ 
 
ll has[maxn];		//每种化肥的映射,以防止同一区域内发生   3的整数倍不是加3加出来的,而是同时加1,加2加出来的 
 

int main(){
	int n,m,t,x1,x2,y1,y2,k;
	cin>>n>>m>>t;
	//对hash初始化(重新编号) 
	srand(time(0));
	for(int i=1;i<=n*m;i++)
		has[i]=(ll)i*rand()+maxn;	//数越大,越不容易重复 
	
	//用的二维动态数组,把a[i][j]记录原值,而b[i][j]则记录加上每次的化肥。
	//动态数组初始化 
	ll **a=new ll*[n+10];
	ll **dp=new ll*[n+10]; 
	for(int i=0;i<=n+1;i++){	//动态数组必须初始化为0 (为什么到n+1)防止后面修改越界,不需要加if了 
		a[i]=new ll[m+2];
		dp[i]=new ll[m+2];
		for(int j=0;j<=m+1;j++){
			a[i][j]=dp[i][j]=0;
			if(i>0&&i<=n&&j>0&&j<=m)cin>>a[i][j],a[i][j]=has[a[i][j]];	 
		}
	}
	 while(t--){
	 	cin>>x1>>y1>>x2>>y2>>k;
	 	ll tmp=has[k]; 
	 	//根据定义一维差分bi=ai-ai-1
		 //若修改ai一个区间的值,只修改bl(+k)和br+1(-k)。
		 //拓展到二维差分b(i,j)=a(i,j)-a(i-1,j)-a(i,j-1)+a(i-1,j-1)
		 //若修改a(i,j)一个区域的值,只修改 行的l,r+1,列的l,r+1,中这四个数组合成的四个坐标点。若(l|r+1,l|r+1)为正,(l|r+1,r+1|l)为负
		 
		 //下面代码作用:此时dp为bi,(修改一个区域的值) 
	 	dp[x1][y1]+=tmp;
        dp[x1][y2+1]-=tmp; 
        dp[x2+1][y1]-=tmp;
        dp[x2+1][y2+1]+=tmp;
	 } 
	 ll ans=0; 
	 for(int i=1;i<=n;i++){	//查询是否为hash[k]的整数倍,不是则+1 
        for(int j=1;j<=m;j++){
            dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]; 	//此时dp为ai 
            if(dp[i][j]%a[i][j])
                ans++;
        }
    }
    cout<<ans; 
	 
}

思路参考:
https://blog.csdn.net/kzn2683331518/article/details/81154399?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值