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\n",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*/
康复训练中~欢迎交流!