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