codeforces 1151 E. Number of Components(思维||单点贡献)

本文深入解析Codeforces比赛中的E题,提供一种高效算法解决区间贡献问题,避免重复计算,通过巧妙利用数字特性,实现O(n)复杂度的求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://codeforces.com/contest/1151/problem/E
题意:
n个数字,每两个数字之间看做连接在一起, f ( l , r ) f(l,r) f(l,r)表示只留下l~r的数字的连通块的大小,求 ∑ l = 1 n ∑ r = l n f ( l , r ) \sum_{l=1}^{n} \sum_{r=l}^{n} f(l, r) l=1nr=lnf(l,r) (l<=r)

这道题自己做的时候一脸懵逼,无从下手,看了题解才恍然大悟… 感觉是个固定的套路了
思路:首先肯定不能o(n2)枚举边界,那么考虑如何遍历每个数字的时候就能知道它对答案的贡献了,那么思考什么时候才会有贡献产生
当它被包含进一个区间时就会有贡献,但是显然这样会重复计算,那么只考虑该数能作为某些区间的左右端点的时候
其实只用考虑作为单独一个端点即可,当我们考虑x作为左端点的时候,必然会有一个y作为右端点与之对应,那么如果我们枚举到y时又计算了y作为右端点,那么显然该区间就被重复计算了一次,所以只需要考虑单独一个端点
以左端点为例子:
1.当 a [ i − 1 ] &lt; a [ i ] a[i-1]&lt;a[i] a[i1]<a[i] a [ i − 1 ] &lt; l &lt; = a [ i ] a[i-1]&lt;l&lt;=a[i] a[i1]<l<=a[i]并且 r &gt; = a [ i ] r&gt;=a[i] r>=a[i]
2.当 a [ i − 1 ] = a [ i ] a[i-1]=a[i] a[i1]=a[i] 无法作为左端点
3.当 a [ i − 1 ] &gt; a [ i ] a[i-1]&gt;a[i] a[i1]>a[i] l &lt; = a [ i ] l&lt;=a[i] l<=a[i]并且 r &lt; a [ i − 1 ] r&lt;a[i-1] r<a[i1]
计算出所有贡献求和即可 代码很短…

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
 
typedef long long ll;
typedef pair<char, ll> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 100;
const int mod = 1e9+7;
const int base=131;
tr1::unordered_map<ll,ll> mp;
inline ll mul(ll x,ll y) { return (x*y-(ll)((long double)x*y/mod)*mod+mod)%mod;}
inline ll ksm(ll a,ll b) {ll ans=1;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a),b>>=1;}return ans;}
 
ll n,m;
ll a[N],b[N];
ll num[N],sum[N];
ll k,ans;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		if(a[i]>a[i-1]) ans+=(a[i]-a[i-1])*(n-a[i]+1);
		if(a[i]<a[i-1]) ans+=a[i]*(a[i-1]-a[i]);
	}
	cout<<ans;
 
 
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值