前缀和与差分 ST

前缀和很好理解,其实也就是为了后期方便计算

#include<iostream>
using namespace std;
const int  N=100010;
int n,m;
int a[N],s[N];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		s[i]=s[i-1]+a[i];
	}
	while(m--)
	{
		int l,r;
		cin>>l>>r;
		cout<<s[r]-s[l-1];
	}
	return 0;
}

一维的很好理解

#include<iostream>
using namespace std;
const int N=1010;
int n,m,q;
int s[N][N];
int main()
{
	cin<<n<<m<<q;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin<<s[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
	}
	while(q--)
	{
		int x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		cout<<s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
	}
}

P1115
最大子段和:
这个把每个段的和求出来,然后循环着去减,应该可以解决的,但我猜必定超时
好一点的办法:
用一点点dp的思想:就是说每次新加入进来一个,那么对于这样一个长度的段,它的最大子列长度是:原有的(>0)+他自己 他自己
当他选择后者的时候,前面的就戛然而止了,所以需要ans存每一次的最大值,防止丢掉,其实也就是是sum>0,再继续加

#include<iostream>
#include<math.h>
using namespace std;
long long int h,maxn[2000001],a[2000001],ans=-99999999;
int main()
{
	cin>>h;
	for(int i=1;i<=h;i++)
	{
	cin>>a[i];
	maxn[i]=max(a[i],maxn[i-1]+a[i]);

	ans=max(ans,maxn[i]);
	}	
	cout<<ans;
	return 0;
}

P3397
这个题目就是非常明显的的用二维前缀来做,一开始这个矩形全部都是0,然后接下去就直接循环+1
没意思

#include<iostream>
using namespace std;
int main()
{
	int n,m,a[1100][1100]={0},x1,x2,y1,y2;
	cin>>n>>m;
	
	for(int i=0;i<m;i++)
	{
		cin>>x1>>y1>>x2>>y2;
		for(int i=x1-1;i<=x2-1;i++)
		{
			for(int j=y1-1;j<=y2-1;j++)
			{
				a[i][j]++;
			}
		}
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
 } 

P1719

求最大加权矩阵,先把每个以自己为右下角大的矩形里面的值给算出来,用循环算,然后或许可以循环两遍,把每一种的都算出来,四重循环
具体一点来说
p,k要放在是较大的的那两个,其他的是上面的,然后每一次更新最大值

#include<iostream>
using namespace std;
 int m,sum[130][130]={0},a[130][130],maxn=-109,hh;
int main()
{
  cin>>m;
  for(int i=1;i<=m;i++)
  {
  	for(int j=1;j<=m;j++)
  	{
  		cin>>a[i][j];
  		
	  }
  }	
  sum[1][1]=a[1][1];
  for(int i=1;i<=m;i++)
  {
  	for(int j=1;j<=m;j++)
  	{
  		sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
	}
  }	
  for(int i=1;i<=m;i++)
  {
  	for(int j=1;j<=m;j++)
  	{
  		for(int k=i;k<=m;k++)
  		{
  			for(int p=j;p<=m;p++)
  			{
  				hh=sum[k][p]-sum[k][j-1]-sum[i-1][p]+sum[i-1][j-1];
				  maxn=max(maxn,hh); 
			  }
		  }
	  }
  }
   
  cout<<maxn;
  
}

P2880
千呼万唤使出来的ST表

#include<bits/stdc++.h>
using namespace std;
int lxy[180010][22],hrb[180010][21],n,m,i,j,k,l,r;
int ST(int l,int r)
{
    int s=log2(r-l+1),x,y;
    x=max(lxy[l][s],lxy[r-(1<<s)+1][s]);
    y=min(hrb[l][s],hrb[r-(1<<s)+1][s]);
    return x-y;}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    scanf("%d",&lxy[i][0]),hrb[i][0]=lxy[i][0];
	for(i=1;i<=21;i++)
	for(k=1;k+(1<<i)<=n+1;k++)
	{
		lxy[k][i]=max(lxy[k][i-1],lxy[k+(1<<(i-1))][i-1]);
		hrb[k][i]=min(hrb[k][i-1],hrb[k+(1<<(i-1))][i-1]);
        }
	for(i=1;i<=m;i++)	{
		scanf("%d%d",&l,&r);
		printf("%d\n",ST(l,r));
	}
	return 0;//结束
}

s指的是x,y之间距离可以取得2的多少次
根据你的预处理:就是两次从小到大的循环,外循环是2的多少次,最多不过21,内循环是确保他不超的,可以得到其从i个元素开始长度位为2^j个元素的最值

RMQ(Li,Ri)=max(f[Li][x],f[Ri-2^x+1][x])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值