zoj 3872 Beauty of Array

题意:

求一个数组的所有连续子串中不同的数字的和。

思路:

考虑每一个数字对于最终结果的贡献。

假设dp[i]表示以a[i]结尾的串的和,那么有dp[i] = dp[i-1] + a[i] * k。

这里的k,如果当前的a[i]没有在前面出现过,那么对结果的贡献肯定是k = i次,因为以它结尾的字串有i个;

但是如果出现过,假设它上一次出现的位置是pre,那么对结果的贡献就是k = i - pre喽。

考虑串 1 2 3 2 3,当我考虑最后一个3的时候,以它为结尾的子序列有:

1 2 3 2 3

2 3 2 3

3 2 3

2 3

3

显然前3个序列中有两个3,所以在前三个序列中,3的贡献已经被前面的3给计算了,所以只有后两个序列才能算当前的3的贡献。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <map>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N = 1e5 + 10;
 8 int a[N];
 9 ll dp[N];
10 int main()
11 {
12     int t;
13     scanf("%d",&t);
14     while (t--)
15     {
16         memset(dp,0,sizeof(dp));
17         map<int,int> mp;
18         int n;
19         scanf("%d",&n);
20         for (int i = 1;i <= n;i++)
21         {
22             scanf("%d",&a[i]);
23         }
24         for (int i = 1;i <= n;i++)
25         {
26             dp[i] = dp[i-1] + (ll)(i-mp[a[i]]) * a[i];
27             mp[a[i]] = i;
28         }
29         ll ans = 0;
30         for (int i = 1;i <= n;i++) ans += dp[i];
31         printf("%lld
",ans);
32     }
33     return 0;
34 }
35 /*
36 3
37 5
38 1 2 3 4 5
39 3
40 2 3 3
41 4
42 2 3 3 2
43 8*/
原文地址:https://www.cnblogs.com/kickit/p/9000080.html