• 【51nod】区间求和


    LYK在研究一个有趣的东西。

    假如有一个长度为n的序列,那么这个序列的权值将是所有有序二元组i,j的 Σajai 其中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 }
    View Code
  • 相关阅读:
    Doing Homework 简单dp&&状态压缩
    嫖裤子序列
    王宁宁宁
    友军寻路法
    Viviani
    ccf 201909-3
    ccf 201909-5
    链式前向星
    ccf-201909-04
    ccf -201909-2
  • 原文地址:https://www.cnblogs.com/dirge/p/6111237.html
Copyright © 2020-2023  润新知