差分与前缀和习题

目录

 

1.最高的牛

2.蒜头君的数轴

3.Covered Points Count


1.最高的牛

 

题目连接:https://www.acwing.com/problem/content/description/103/

题意:现在有n头牛,我们只知道其中的最高牛的高度和位置,现在给了m个关系,每个关系输入a,b.表示牛a和牛b可以互相看见

俩头牛能互相看见的条件是俩头牛之间的牛头比他们矮,求每头牛最大的身高

注意不会出现交叉的情况如下图所示:

思路:首先初始化每头牛的高度为最高牛的高度H,求一个差分数组d,对于每次输入的a,b,我们让[a,b](不包括a,b)之间的牛的身高比俩边的少1就行,这就转为了区间加数的问题,差分就解决了。

code:

#include<bits/stdc++.h>

using namespace std;

const int N=1e4+10;
int d[N];
bool vis[N][N];
int main()
{
    int n,p,h,m;
    cin>>n>>p>>h>>m;
    d[1]+=h;
    int a,b;
    while(m--){
        cin>>a>>b;
        if(a>b) swap(a,b);
        if(!vis[a][b]){
            d[a+1]--;
            d[b]++;
            vis[a][b]=1;
        }
    }
    
    // for(int i=1;i<=n;i++) cout<<d[i]<<" ";
    for(int i=1;i<=n;i++){
        d[i]+=d[i-1];
        cout<<d[i]<<endl;
    }
    return 0;
}c

 

2.蒜头君的数轴

题目连接:https://nanti.jisuanke.com/t/A1633

题意:最多只有一个相邻点的距离和其他的不同,问最少加多少点

思路:有一个距离和其他的不同肯定比所有距离都相同要加的点少,枚举一下[1,n-1]每个距离,剩下的n-2个距离要相同,所以要求一下剩下n-2个距离的最大公约数GCD,直接求会超时,所以需要用一下前缀gcd和后缀gcd,前缀gcd和后缀gcd 在求一下gcd就算出来GCD了,如图

 

sum:出了枚举的距离外所的距离和 。 sum/GCD:长度为GCD 的距离的段数     现在有n-2段 ,所以需要加的点数为sum/GCD-(n-2). 最后每次更新这个最小值 

code:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=1e5+10;
int a[N],d[N];
int pre[N],suf[N];
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n);
	ll sum=0;
	for(int i=1;i<n;i++){
		d[i]=a[i]-a[i-1];//每一段的距离 
		sum+=d[i];
	}
//	cout<<sum<<endl;
	//预处理前缀gcd和后缀gcd 
	for(int i=1;i<n;i++) pre[i]=__gcd(d[i],pre[i-1]);
	for(int i=n-1;i>=1;i--) suf[i]=__gcd(d[i],suf[i+1]);
	ll ans=0x3f3f3f3f;
	for(int i=1;i<n;i++){
		sum-=d[i];
//		cout<<sum<<" "<<__gcd(pre[i-1],suf[i+1])<<endl;
		ans=min(ans,sum/(ll)__gcd(pre[i-1],suf[i+1])-(n-2));
		sum+=d[i];
	}
	cout<<ans<<endl; 
	return 0;
}

3.Covered Points Count

题目连接:

题意:现在有n条线段 求被覆盖k次的点的个数 k∈[1,n]

思路:点的位置比较大10^18,不能用数组来做差分,但是可以用map来做,遍历map,维护一下前缀和sum,然后每次更新一下答案数组即可。

code:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=2e5+10;
ll ans[N];
map<ll,ll> mp;
int main()
{
	int n;
	cin>>n;
	ll l,r;
	for(int i=1;i<=n;i++){
		cin>>l>>r;
		mp[l]++;
		mp[r+1]--;
	}
	map<ll,ll>::iterator it=mp.begin();
	ll sum=0;//sum求前缀和 
	for(it;it!=mp.end();it++){
		map<ll,ll>::iterator nex=it;
		nex++;
		if(nex==mp.end()) break;
		sum+=it->second;
//		cout<<ans[1]<<endl;
		ans[sum]+=nex->first-it->first;	
	} 
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值