ZOJ_3872_Beauty of Array_计数原理

考完概率论啦!放假啦!

题意

给一个长度为N的数组,求所有子串中不同数字之和的和是多少。

IO

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer N (1 <= N <= 100000), which indicates the size of the array. The next line contains N positive integers separated by spaces. Every integer is no larger than 1000000.

Output

For each case, print the answer in one line.

分析

计数原理的技巧,从左扫到右,维护每个值最后一次出现的位置,对当前循环到的这一位,找所有包含它并且承认它(承认定义为这个区间内在它之前没有相同数值)的区间的个数,再乘以这个值,即为答案中当前位置贡献的量。这种区间的个数,用合法右边界数量乘以合法左边界数量即可,合法右边界最右到数列最后,最左为当前位置,合法左边界最左为上次出现位置右边的一个位置,最右为当前位置。
代码写的有点挫,然后记录上一次所有数值出现位置的数组只开了mxn大小,理论是不够的,最好用map,不过实际上过了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define mxn 100010
int n;
int a[mxn];
int lst[mxn];
int main(){
    int cs;
    scanf("%d",&cs);
    while(cs--){
        scanf("%d",&n);
        for(int i=0;i<n;++i)    scanf("%d",a+i);
        memset(lst,-1,sizeof(lst));
        long long ans=0LL;
        for(int i=0;i<n;++i){
            ans+=(long long)a[i]*(n-lst[a[i]]-1+((long long)n-i-1)*((long long)i-lst[a[i]]-1));
            lst[a[i]]=i;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
点赞