题意

给你一个长度为 \(n\) 的序列,定义这个序列的权值为 $ \sum_{1 \leq i<j \leq n} a_j - a_i $。

现在给你一个长度为 \(n\) 的序列,当$ a_i=a_j $时,将 $ a_i, a_{i+1}, ... , a_j $ 提出当做一个序列,计算它的权值。统计所有这样的区间的权值和。答案模 \(2^{32}\)。

想法

先考虑对于原题的做法,即对于区间 \([i, j]\) ,每一位都要乘一个系数,即算每一位的系数大小即可。对于 \(i \leq k \leq j\) ,系数 \(= -(j-k) + (k-i) = 2k-(i+j)\) 。回到这道题,对于 \(a_k\),有多少个区间 \([i, j](a_i=a_j, i \leq j)\) 包含了 \(a_k\) 就要加多少个 \(2k\),且要减去这些区间的左端点和右端点的值。

由于减去右端点的值相当于将整个序列翻转然后去减左端点的值,故这里我们只考虑左端点。减右端点的情况我们倒着跑一边即可。

首先我们可以预处理出每个数从左往右(\(lrk\))/从右往左(\(rrk\))数是第几次出现,它的前驱(\(pre\))/后继(\(next\))分别在哪。

方便起见,我们不妨考虑 \([i, i]\) 这样的区间也合法。考虑序列3 3 3 3, \(f_i\) 表示要减的左端点的值的和。\(f_1 = 1*4 = 4, f_2 = f_1 + 2*3 - 1 = 9, f_3 = f_2 + 3*2 - (1 + 2)=12, f_4 = f_3 + 4*1 - (1 + 2 + 3)=10\) 。观察可知每次加上了一个 \(i*rrk[i]\) ,又减掉了 \(i\) 之前出现的值为 \(a_i\) 的下标和。为什么呢?因为我们一开始假想 \(i\) 到序列末尾都覆盖上了 \(i\) ,中间遇到一个 \(a_i\) 的时候就要让其中的一个区间停止更新。那么我们定义 \(decA[i]\) 表示 \(i\) 之前出现的值为 \(a_i\) 的下标和,转移方程为 \(decA[i] = decA[pre[i]] + pre[i]\)。一般的,33之间还有很多其他的数,那么我们减掉 \(decA[i]\) 的时候不是下一次 \(a[i]\) 出现的时候,而是 \(i+1\) 就必须减掉,不然覆盖的区间就是 \([i, next[i])\) 了,实际上应该是 \([i, i]\) 。

故可以得出转移方程 $$f[i] = f[i-1] + i*rrk[i] - decA[next[i-1]]$$

这里有一个问题,就是如果 \(rrk[i] = 1\) 的时候 \(next[i]\) 不存在, 减 \(decA[next[i]]\) 的时候会出错。那我们自己造一个 \(next[i]\) 嘛...特判一下就好了。

最后是 \(2k\) 的个数,由于以上我们统计的是左端点的值的总和,那么我们把这个值改成 \(1\) 不就是区间的个数了吗。 \(decA[i]\) 的转移方程改成 \(decA[i] = decA[pre[i]] + 1\) 即可。

怕gg所以写了个快速乘...不过好像不用也没问题...

记得用unsigned int存答案,最好写个读入优化。

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define ll long long
#define db double
#define uint unsigned int
#define N 3000100
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define swap(T, a, b) ({T ttt = a; a = b; b = ttt;})
int n, lrk[N], rrk[N], pre[N], next[N], pos[N];
uint a[N], decA[N], decB[N], f[N], g[N], Ans = 0;
void G(uint &w) {
w = 0; char c = getchar();
while (c > '9' || c < '0') c = getchar();
while (c >= '0' && c <= '9') { w = w * 10 + c - '0'; c = getchar(); }
}
uint Mult(uint a, uint b)
{
uint s = 0;
while (b) {
if (b & 1) s += a;
a += a; b >>= 1;
}
return s;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
G(a[i]);
memset(pos, 0, sizeof(pos));
for (int i = 1; i <= n; i++)
{
pre[i] = pos[a[i]]; pos[a[i]] = i;
lrk[i] = lrk[pre[i]] + 1;
decA[i] = decA[pre[i]] + pre[i];
}
memset(pos, 0, sizeof(pos));
for (int i = n; i >= 1; i--)
{
next[i] = pos[a[i]]; pos[a[i]] = i;
rrk[i] = rrk[next[i]] + 1;
decB[i] = decB[next[i]] + next[i];
}
for (int i = 1; i <= n; i++)
{
if (rrk[i] == 1)
{
next[i] = i+n; pre[i+n] = i;
lrk[next[i]] = lrk[i] + 1;
decA[i+n] = decA[i] + i;
}
if (lrk[i] == 1)
{
pre[i] = i+n*2; next[i+n*2] = i;
rrk[pre[i]] = rrk[i] + 1;
decB[i+n*2] = decB[i] + i;
}
}
for (int i = 1; i <= n; i++)
f[i] = f[i-1] + i*rrk[i] - decA[next[i-1]];
for (int i = n; i >= 1; i--)
g[i] = g[i+1] + i*lrk[i] - decB[pre[i+1]];
for (int i = 1; i <= n; i++)
f[i] = f[i] + g[i] - i*2;
memset(g, 0, sizeof(g));
memset(decA, 0, sizeof(decA));
for (int i = 1; i <= n; i++)
{
decA[i] = decA[pre[i]] + (pre[i] >= 1 && pre[i] <= n);
if (rrk[i] == 1) decA[i+n] = decA[i] + 1;
}
for (int i = 1; i <= n; i++)
{
g[i] = g[i-1] + rrk[i] - decA[next[i-1]];
f[i] = Mult(g[i] - 1, i) * 2 - f[i];
Ans += Mult(f[i], a[i]);
}
std::cout << Ans << std::endl;
return 0;
}

51nod 1712 区间求和的更多相关文章

  1. 51Nod 1680 区间求和 树状数组

    题意: 给出一个长度为\(n\)的数列\(A_i\),定义\(f(k)\)为所有长度大于等于\(k\)的子区间中前\(k\)大数之和的和. 求\(\sum_{k=1}^{n}f(k) \; mod \ ...

  2. 【51nod】区间求和

    LYK在研究一个有趣的东西. 假如有一个长度为n的序列,那么这个序列的权值将是所有有序二元组i,j的 Σaj−ai 其中1<=i<j<=n. 但是这个问题似乎太简单了. 于是LYK想 ...

  3. 51nod 1680区间求和 (dp+树状数组/线段树)

    不妨考虑已知一个区间[l,r]的k=1.k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间) 那么如果加入一个新的数字a[i](i = r+1) 则新区间[l, i]的答案为 ...

  4. POJ 2823 Sliding Window 线段树区间求和问题

    题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...

  5. POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)

    A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...

  6. vijos1740 聪明的质监员 (二分、区间求和)

    http://www.rqnoj.cn/problem/657 https://www.vijos.org/p/1740 P1740聪明的质检员 请登录后递交 标签:NOIP提高组2011[显示标签] ...

  7. LightOJ 1112 Curious Robin Hood (单点更新+区间求和)

    http://lightoj.com/volume_showproblem.php?problem=1112 题目大意: 1 i        将第i个数值输出,并将第i个值清0 2 i v     ...

  8. POJ 3468 A Simple Problem with Integers(线段树区间求和)

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  9. poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)

    转载请注明出处:http://blog.csdn.net/u012860063 Description You have N integers, A1, A2, ... , AN. You need ...

随机推荐

  1. iOS 用户的隐私数据-privacy-sensitive data

    1  Xcode 报错:This app has crashed because it attempted to access privacy-sensitive data without a usa ...

  2. BZOJ 2093: [Poi2010]Frog

    Description 从一个点到达与他距离第 \(k\) 小的点,问从每个点跳 \(m\) 次到达那个点. Sol 队列+倍增. 保持队列里的元素个数为 \(k\) ,从前往后扫不难发现左右端点都是 ...

  3. python模块引用问题(比较杂乱,懒得整理)

    1 在stackoverflows摘抄 If the import module in the same dir, use e.g: from . import core If the import ...

  4. selenium测试框架使用xml作为对象库

    之前已经写过一篇: selenium测试框架篇,页面对象和元素对象的管理 上次使用的excel作为Locator对象管理,由于excel处理不够方便,有以下缺点: 不能实现分page 加载Locato ...

  5. iOS常用第三方开源框架和优秀开发者博客等

    博客收藏iOS开发过程好的开源框架.开源项目.Xcode工具插件.Mac软件.文章等,会不断更新维护,希望对你们有帮助.如果有推荐或者建议,请到此处提交推荐或者联系我. 该文档已提交GitHub,点击 ...

  6. Windows Server 2008 R2 IIS7.5 部署 MVC HTTP 404.0 Not Found 错误

    如图 在Windows Server 2008 R2 IIS7.5 部署 MVC HTTP 404.0 Not Found 错误,在Win7环境下测试正常,在百度中查找相关解决方法,如修改配置文件等, ...

  7. IIS6.0 web.config

    IIS6.0环境下,要把托管管道模式 改为:经典. <?xml version="1.0" encoding="UTF-8"?> <confi ...

  8. ios常用的第三方库

    ios开发中有可能用到的第三方库进行记录一下: 注:资料信息来源于网络 自己整理  https://developer.apple.com/reference(苹果官方文档) https://gith ...

  9. Guidance of Set up FTP Server

    Step 1. Create a FTP folder in your C disk, named "FTPReport"(an example) Step 2. Install ...

  10. 关于for循环------swift3.0

    在程序开发当中,for循环使用的频率无疑是最高的.常用的swift循环是递增式遍历.当然各种循环,swift都能办到.但其大多采用关键字形式实现,大部分开发者更喜欢直接使用C式循环代码.在swift3 ...