LYK在研究一个有趣的东西。
假如有一个长度为n的序列,那么这个序列的权值将是所有有序二元组i,j的 Σaj−ai 其中1<=i<j<=n。
但是这个问题似乎太简单了。
于是LYK想在所有有序二元组k,l中若ak=al,其中1<=k<l<=n,则将 a{k},a{k+1},...,a{l} 提出当做一个序列,计算它的权值。
并统计所有这样的区间的权值和。
由于答案可能很大,你只需要将答案对2^32取模即可。
建议使用读入优化。
Input
第一行一个整数n(1<=n<=1000000),接下来一行n个数ai(1<=ai<=1000000)表示LYK的序列。
Output
一行表示答案。
Input示例
5 3 4 5 5 3
Output示例
2
题解:每次取出一个区间[l, r],发现a[i] 产生的贡献为 2*i-l-r. 预处理一下prenum[], presum[], prenum[i]表示[1, i]有多少个和a[i]相同, presum[i]表示[1, i]与a[i]相同的数所在的下标和,同理预处理出nexnum[], nexsum[].O(n)扫一遍维护一下l, r, 2*i即可递推出各个值。
1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <string.h> 5 6 using namespace std; 7 #define ll unsigned long long 8 const int N = 1e6+5; 9 int n, a[N]; 10 int pre[N], nex[N], pos[N]; 11 int prenum[N], nexnum[N]; 12 int presum[N], nexsum[N]; 13 int fl[N], fr[N], f[N]; 14 15 int main(){ 16 scanf("%d", &n); 17 for(int i = 1; i <= n; i++) scanf("%d", a+i); 18 19 memset(pos, 0, sizeof(pos)); 20 for(int i = 1; i <= n; i++){ 21 pre[i] = pos[ a[i] ]; 22 prenum[i] = prenum[ pre[i] ]+1;//前面的个数 23 presum[i] = presum[ pre[i] ]+i;//前面的下标和 24 pos[ a[i] ] = i; 25 } 26 memset(pos, 0, sizeof(pos)); 27 for(int i = n; i; i--){ 28 nex[i] = pos[ a[i] ]; 29 nexnum[i] = nexnum[ nex[i] ]+1; 30 nexsum[i] = nexsum[ nex[i] ]+i; 31 pos[ a[i] ] = i; 32 } 33 34 for(int i = 1; i <= n; i++){ 35 fl[i] = fl[i-1]; 36 fl[i] += i*nexnum[i]; 37 fl[i] -= presum[i-1]; 38 } 39 for(int i = n; i; i--){ 40 fr[i] = fr[i+1]; 41 fr[i] += i*prenum[i]; 42 fr[i] -= nexsum[i+1]; 43 } 44 45 for(int i = 1; i <= n; i++) 46 f[i] = f[i-1]+nexnum[i]-prenum[i-1]; 47 unsigned int ans = 0; 48 for(int i = 1; i <= n; i++){ 49 //printf("i %d: %d %d %d ", i, fl[i], fr[i], f[i]); 50 ans += a[i]*(2*i*f[i]-fl[i]-fr[i]); 51 } 52 printf("%u ", ans); 53 return 0; 54 }