ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第二章 前缀和、差分与离散化 例题

2022-04-30 09:01:51  阅读:198  来源: 互联网

标签:10 fr 前缀 int res 差分 rd cch 例题


第二章 前缀和、差分与离散化 例题

*T1 P1719 最大加权矩形

题目描述:

给定一个n*n的矩阵,求出其中元素和最大的一块子矩阵的元素和。

\(n\le120\)

思路1: 矩阵前缀和 \(O(n^4)\)

先执行一次矩阵前缀和。

然后依次枚举每对点,\(O(1)*n^4\)遍历每一个子矩阵。

*思路二: \(O(n^3)\)

枚举起始行(行a),然后从这行Qwq开始往后枚举终止行(行b)。

对于每个行a的每一纵列执行前缀和,然后在求和到某一行b时,从左到右dp寻找恰好包含a~b所有行的矩阵中的最大子矩阵,再在其中寻找最大值即可。

Code:

#include<bits/stdc++.h>
#define ll long long
#define fr(i,r) for(int i=1;i<=r;++i)
#define For(i,l,r) for(int i=l;i<=r;++i)
#define Rof(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N=130,Inf=0x7fffffff;
char cch;
int res,zf;
inline int rd()
{
	while((cch=getchar())<45);
	if(cch^45)res=cch^48,zf=1;
	else res=0,zf=-1;
	while((cch=getchar())>=48)res=(res*10)+(cch^48);
	return res*zf;
}

int n=rd(),mat[N][N];
int sum[N];
int dplst,dppos,mx=-Inf;

int main()
{
	fr(i,n)fr(j,n)mat[i][j]=rd();
	fr(i,n)//起始行
	{
		memset(sum,0,sizeof(sum));
		For(j,i,n)//终止行
		{
			dplst=0;
			fr(k,n)
			{
				sum[k]+=mat[j][k];
				dppos=max(dplst+sum[k],sum[k]);
				mx=max(mx,dppos);
				dplst=dppos;
			}
		}
	}
	cout<<mx;
	return 0;
}

T2 P

题目描述:

思路1:

思路2:

Code:


T3 P2367 语文成绩

题目描述:

给定一个n项数列,p次修改,每次将一个给定区段都加上一个数值,求最后数列中的最小值。

\(p\le n\le 5*10^6\)

思路:

差分裸题。

Code:

#include<bits/stdc++.h>
#define ll long long
#define fr(i,r) for(int i=1;i<=r;++i)
#define For(i,l,r) for(int i=l;i<=r;++i)
#define Rof(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N=5e6+10,Inf=0x7fffffff;
char cch;
int res,zf;
inline int rd()
{
	while((cch=getchar())<45);
	if(cch^45)res=cch^48,zf=1;
	else res=0,zf=-1;
	while((cch=getchar())>=48)res=(res*10)+(cch^48);
	return res;
}

int n=rd(),p=rd(),a[N],c[N];
int x,y,z;
int mi=Inf;

int main()
{
	fr(i,n) a[i]=rd();
	while(p--)
	{
		x=rd(),y=rd(),z=rd();
		c[x]+=z,c[y+1]-=z;
	}
	fr(i,n)
	{
		c[i]+=c[i-1];
		mi=min(mi,c[i]+a[i]);
	}
	cout<<mi;
	return 0;
}

T4 P3397 地毯

题目描述:

一个n*n的矩阵,初始为0。m次修改,每次将一个给定范围内的所有数+1,求最后的矩阵。

\(n,m\le1000\)

思路:

逐行差分。

Code:

#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,a[1002][1002],xs,ys,xe,ye,sum;
int main()
{
	scanf("%d%d",&n,&m);
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d%d",&xs,&ys,&xe,&ye);
		for(j=xs;j<=xe;j++)
		{
			a[j][ys]++;
			a[j][ye+1]--;
		}
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			a[i][j]+=a[i][j-1];
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
}

*T5 P1496 火烧赤壁

题目描述:

给定n个区间a~b,求这些区间覆盖的总长度。

\(1≤n≤2×10^4\ ,\ -2^{31} \le a \le b \lt 2^{31}\)

思路1:

image

如上图所示,上方的情况可以转换成下方的情况。

所以起点终点的顺序对答案不产生影响。

于是对起点和终点分别进行排序,累加每一条线段的长度。若与前一条线段有重复区域则减去重复部分。

思路2: 离散化

</>

Code: 思路一

#include<bits/stdc++.h>
#define ll long long
#define fr(i,r) for(int i=1;i<=r;++i)
#define For(i,l,r) for(int i=l;i<=r;++i)
#define Rof(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N=2e4+10,Inf=0x7fffffff;
char cch;
int res,zf;
inline int rd()
{
	while((cch=getchar())<45);
	if(cch^45)res=cch^48,zf=1;
	else res=0,zf=-1;
	while((cch=getchar())>=48)res=(res*10)+(cch^48);
	return res*zf;
}

int n=rd();
ll ans;
int a[N],b[N];

int main()
{
	fr(i,n)a[i]=rd(),b[i]=rd();
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	
	b[0]=-Inf;
	fr(i,n)
	{
		ans+=(b[i]-a[i]);
		if(b[i-1]>a[i])ans-=(b[i-1]-a[i]);
	}
	cout<<ans;
	return 0;
}

!<离散化> T6 P1955 [NOI2015] 程序自动分析

题目描述:

给定n组形如 \(a_i=a_j\) , \(a_1\not=a_j\) 的约束条件,判断所有约束条件间是否存在矛盾。

\(共\ \ T\le10\ \ 组数据,n\le10^6,i,j\le10^9\)

思路:

离散化+并查集。

先将所有相等的数相联通,对于不等于的约束直接判断父亲是否相同即可。

Code:

#include<bits/stdc++.h>
#define ll long long
#define fr(i,r) for(int i=1;i<=r;++i)
#define For(i,l,r) for(int i=l;i<=r;++i)
#define Rof(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N=1e6+10,Inf=0x7fffffff;
char cch;
int res,zf;
inline int rd()
{
	while((cch=getchar())<45);
	if(cch^45)res=cch^48,zf=1;
	else res=0,zf=-1;
	while((cch=getchar())>=48)res=(res*10)+(cch^48);
	return res*zf;
}

int T=rd();
int n;

struct ques
{
	int x,y,opt;
}a[N];


int fa[N<<1];//初始化到2n!最多会出现2n个不同数
inline int getf(int v)
{
	if(v==fa[v])return v;
	return fa[v]=getf(fa[v]);
}
inline void combine(int x,int y)
{
	x=getf(x),y=getf(y);
	if(x^y)fa[x]=y;
}

int ls[N<<1],p;
inline void lsh()
{
	sort(ls+1,ls+n*2+1);//离散化需要先进行排序
	p=unique(ls+1,ls+n*2+1)-ls;//p记录为不重项末项的下一位下标
	fr(i,n)
	{
		a[i].x=lower_bound(ls+1,ls+p,a[i].x)-ls;//在去重后的有序数列中,第一个大于或等于一个数的位置即为它的相对大小
		a[i].y=lower_bound(ls+1,ls+p,a[i].y)-ls;
	}
}

inline bool cmp(ques xx,ques yy)
{
	return xx.opt>yy.opt;
}
int main()
{
	while(T--)
	{
		memset(a,0,sizeof(a));
		n=rd();
		fr(i,n)
		{
			a[i].x=rd(),a[i].y=rd();
			a[i].opt=rd();
			ls[(i<<1)-1]=a[i].x;//将数据载入离散化数组
			ls[i<<1]=a[i].y;
		}
		
		lsh();
		
		sort(a+1,a+n+1,cmp);//把'='操作放到前面
		fr(i,p)fa[i]=i;//并查集重置
		
		int i=1;
		while(a[i].opt) combine(a[i].x,a[i].y),++i;
		
		bool flag=1;
		while(i<=n)
		{
			if(getf(a[i].x)==getf(a[i].y))
			{
				flag=0;
				cout<<"NO\n";
				break;
			}
			++i;
		}
		if(flag)cout<<"YES\n";
	}
	return 0;
}

! 离散化:

将所有出现的数存入一个单独的离散化数组,先进行排序,利用unique函数去除重复出现的数。再进行排序,排序后每个数值所对应的相对大小即对应着其在新数组中的下标。

T7 P

题目描述:

思路:

Code:


标签:10,fr,前缀,int,res,差分,rd,cch,例题
来源: https://www.cnblogs.com/hankpeng/p/16209417.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有