51nod1712 区间求和
http://www.51nod.com/Challenge/Problem.html#problemId=1712
先考虑题面中的简化问题。
对于\(i\in [1,n]\),\(a_i\)的贡献为\(a_i*(i-1)-a_i*(n-i)\)
那么对于\(i\in [l,r](a_l=a_r)\),贡献为\(a_i*(i-l)-a_i*(r-i)=2i*a_i-a_i(l+r)\)
这个式子只需要统计4个东西就可以\(O(n)\)计算了。
- \(i\)左侧\(a_l\)的个数\(A\)
- \(i\)右侧\(a_r\)的个数\(B\)
- \(i\)左侧\(a_l\)的\(l\)之和\(C\)
- \(i\)右侧\(a_r\)的\(r\)之和\(D\)
那么对答案的贡献就是\(2*i*a_i*A*B-a_i*(BC+AD)\)
统计一下\(A,B,C,D\)即可。
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x * f;
}
typedef unsigned int uint;
const int N = 1000010;
int n, lim, a[N];
uint num[N], sum[N], numl[N], numr[N], suml[N], sumr[N];
uint Sum, Num;
int main() {
n = read();
for(int i = 1; i <= n; ++i) {
a[i] = read();
numr[a[i]]++; sumr[a[i]] += i;
}
uint ans = 0;
for(int i = 1; i <= n; ++i) {
numl[a[i]]++; suml[a[i]] += i;
Num -= num[a[i]];
num[a[i]] = numl[a[i]] * numr[a[i]];
Num += num[a[i]];
Sum -= sum[a[i]];
sum[a[i]] = suml[a[i]] * numr[a[i]] + sumr[a[i]] * numl[a[i]];
Sum += sum[a[i]];
ans += 2 * i * a[i] * Num - a[i] * Sum;
numr[a[i]]--; sumr[a[i]] -= i;
Num -= num[a[i]];
num[a[i]] = numl[a[i]] * numr[a[i]];
Num += num[a[i]];
Sum -= sum[a[i]];
sum[a[i]] = suml[a[i]] * numr[a[i]] + sumr[a[i]] * numl[a[i]];
Sum += sum[a[i]];
}
printf("%u\n", ans);
}
51nod1712 区间求和的更多相关文章
- POJ 2823 Sliding Window 线段树区间求和问题
题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...
- POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)
A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...
- vijos1740 聪明的质监员 (二分、区间求和)
http://www.rqnoj.cn/problem/657 https://www.vijos.org/p/1740 P1740聪明的质检员 请登录后递交 标签:NOIP提高组2011[显示标签] ...
- LightOJ 1112 Curious Robin Hood (单点更新+区间求和)
http://lightoj.com/volume_showproblem.php?problem=1112 题目大意: 1 i 将第i个数值输出,并将第i个值清0 2 i v ...
- 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 ...
- poj3468 A Simple Problem with Integers(线段树模板 功能:区间增减,区间求和)
转载请注明出处:http://blog.csdn.net/u012860063 Description You have N integers, A1, A2, ... , AN. You need ...
- poj3468树状数组的区间更新,区间求和
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 47174 ...
- D 区间求和 [数学 树状数组]
D 区间求和 题意:求 \[ \sum_{k=1}^n \sum_{l=1}^{n-k+1} \sum_{r=l+k-1}^n 区间前k大值和 \] 比赛时因为被B卡了没有深入想这道题 结果B没做出来 ...
- [用CDQ分治解决区间加&区间求和]【习作】
[前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Par ...
随机推荐
- Centos 7.6 部署 Jumpserver 1.5.0
1.基础设置 # 版本说明 操作系统:centos7. jumpserver: # 升级所有包同时也升级软件和系统内核 yum update -y # selinux配置 setenforce sed ...
- 分布式session一致性
实现思路:当客户端发送请求到服务端后,在后台生成一个token,将token作为key,用户状态信息作为value,存入redis缓存中,并设置过期时间,最后把token返回给客户端 客户端第会保存t ...
- C++ 工程师养成 每日一题fourth (reverse的使用)
题目: 将一句话的单词进行倒置,标点不倒置. 这道题最简单的解法是使用algorithm提供的reverse()函数 具体步骤我写在代码注释里面: #include <string> #i ...
- CLRS10.1-6练习 - 用双栈实现队列
双栈实现队列算法: 分别考虑队列两种操作入队和出队,我们假设使用栈s1 s2, s1用来模拟入队,s2用来模拟出队 入队: 入队操作直接执行s1.push即可 出队: 代码实现 package hel ...
- .net 生成非托管代码
最近在一个老外的程序中看到一段代码,其中使用了System.Runtime.InteropServices.MarshalAs方法进行托管代码与非托管代码之间封装数据,感觉很新颖.特意记录下来,供大家 ...
- 多次执行echarts时出现 there is a chart instance already initialized on the dom
原因,多次使用 echarts.init(document.getElementById(this.options.zid)); 解决方案 设为全局
- ELK学习笔记之Logstash不停机自动重载配置文件
0x00 自动重新加载配置 为了可以自动检测配置文件的变动和自动重新加载配置文件,需要在启动的时候使用以下命令: ./bin/lagstash -f configfile.conf --config. ...
- js 杂症,this with 变量提升
一.this.xx 和 xx 是两回事 受后端语言影响,总把this.xx 和xx 当中一回事,认为在function中,xx 就是this.xx,其实完全两回事: this.xx 是沿着this 原 ...
- 2019-07-22 phpStudy配置虚拟主机
1.右击 phpStudy ->[打开配置文件]->[vhosts-conf]: 2.在里面加入如下代码,并保存: NameVirtualHost *:80 <VirtualHost ...
- 必须修改getdate()格式,判断是否处于两个日期之间
), ) ), )<= 周次结束日期 ), ) -- 这样的格式结果为:2019-09-01 --如果不进行转换,查出来含有日期和时间,否则两个边界无法查询出来