Codeforces Round #553 (Div. 2) E. Guess the Root(dp单点算贡献)

题目链接:https://codeforces.com/contest/1151/problem/E

题意:现在又一条链,每个节点上有个值 A i A_{i} Ai,现在你需要枚举所有值的区间,如果节点值在区间中保留节点,然后将形成的连通块个数加起来。

解题心得:

  1. 看见一个大佬说的很好,看见这种很多连续区间组合求值的问题,其实就是一个单点算贡献的问题。
  2. 枚举每一个节点作为当前连通块左节点能有多少个连续值的区间来表达。
  3. A i > A i − 1 A_{i}>A_{i-1} Ai>Ai1,那么 A i A_{i} Ai作为连通块的左起点,在区间取值左边可以取 [ A i − 1 + 1 , A i ] [A_{i-1} + 1, A_{i}] [Ai1+1,Ai],区间右边取值可以取 [ A i , n ] [A_{i}, n] [Ai,n],总共的取法总数就是 ( A i − A i − 1 ) ∗ ( n − A i + 1 ) (A_{i}-A_{i-1})*(n-A_{i}+1) (AiAi1)(nAi+1)
  4. A i < A i − 1 A_{i}<A_{i-1} Ai<Ai1,那么 A i A_{i} Ai作为连通块的左起点,在区间取值左边可以取 [ A i , A i − 1 − 1 ] [A_{i} , A_{i-1}-1] [Ai,Ai11],区间右边取值可以取 [ 1 , A i ] [1, A_{i}] [1,Ai],总共的取法总数就是 ( A i − 1 − A i ) ∗ A i (A_{i-1}-A_{i})*A_{i} (Ai1Ai)Ai
  5. A i = A i − 1 A_{i}=A_{i-1} Ai=Ai1 A i A_{i} Ai不可能作为连通块的左端点被取到。


#include 
using namespace std;
const int maxn = 2e5+100;
typedef long long ll;

int num[maxn], n;

int main() {
    //freopen("1.in", "r", stdin);
    scanf("%d", &n);
    for(int i=1;i<=n;i++) {
        scanf("%d", &num[i]);
    }

    ll ans = 0;
    for(int i=1;i<=n;i++) {
        if(num[i] > num[i-1]) {
            ans = ans + 1ll * (num[i] - num[i-1]) * (n- num[i] + 1);
        } else if(num[i] < num[i-1]) {
            ans = ans + 1ll * (num[i-1] - num[i]) * num[i];
        }
    }

    cout<<ans<<endl;

    retu

你可能感兴趣的:(动态规划-区间dp)