WC2019 全国模拟赛第一场 T1 题解
由于只会T1,没法写游记,只好来写题解了...
题目链接
题目大意
给你一个数列,每次可以任取两个不相交的区间,取一次的贡献是这两个区间里所有数的最小值,求所有取法的贡献和,对 \(10^9+7\) 取模。
数列长度 \(2\times 10^5\) ,值域 \(1\) ~ \(10^9\) 。
\(O(n^4)\) 做法
预处理区间最小值,枚举选的两个区间。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int M=1000000007;
int n,a[60][60],ans;
int main()
{
int i,j,k,l;
cin>>n;
for (i=1;i<=n;++i)
{
cin>>a[i][i];
}
for (i=1;i<n;++i)
{
for (j=i+1;j<=n;++j)
{
a[i][j]=min(a[i][j-1],a[j][j]);
}
}
for (i=1;i<n;++i)
{
for (j=i;j<n;++j)
{
for (k=j+1;k<=n;++k)
{
for (l=k;l<=n;++l)
{
ans=(ans+min(a[i][j],a[k][l]))%M;
}
}
}
}
cout<<ans;
return 0;
}
\(O(nlogn)\) 做法
warning:接下来的文章里“的”字嵌套情况非常严重,文字叙述比较繁杂,看不懂十分正常,建议看懂一小部分然后自己推。
考虑每个元素作为贡献的区间是哪些,为了把每个区间分给唯一的元素,规定一个区间的贡献是最小值里最靠左的( e.g. 4 3 2 4 2 2 的贡献是 \(3\) 号元素,即最左边的 \(2\) )。所以,可以利用栈在 \(O(n)\) 的时间内预处理出每个元素作为贡献的区间的左端点和右端点的范围:
for (i=1;i<=n;++i)
{
while (top&&a[sta[top]].w>a[i].w)
{
a[sta[top--]].r=i-1;
}
sta[++top]=i;
}
while (top)
{
a[sta[top--]].r=n;
}
for (i=n;i>=1;--i)
{
while (top&&a[sta[top]].w>=a[i].w)
{
a[sta[top--]].l=i+1;
}
sta[++top]=i;
}
while (top)
{
a[sta[top--]].l=1;
}
每个元素作为贡献的区间就是 \([x,y](l_i\le x\le i\le y\le r_i)\),每个元素作为贡献的区间数就是 \(t_i=(i-l_i+1)\times(r_i-i+1)\) 。
然后,将元素按值从大到小排序,就能计算出区间数的后缀和 \(suf[i]\),但一个元素的总贡献并不是 \(t_i\times suf[i+1]\),因为这些区间可能与当前元素作为贡献的区间相交。
注意到,要想和当前元素作为贡献的区间相交,必须 \([x,y](l_i\le x\le y\le r_i)\) ,而这样的区间除了当前元素作为贡献的区间,贡献都排在当前元素之后(值比当前元素大或值相等但位置靠后),所以这样的区间除了当前元素作为贡献的区间,都是我们要找的与当前元素作为贡献的区间相交的贡献更靠后的区间。
注:下面这段话中“相交的区间对”指(与当前元素作为贡献的区间相交的贡献更靠后的区间,当前元素作为贡献的区间)这样的一对区间;“相交的区间”指与当前元素作为贡献的区间相交的贡献更靠后的区间。
接下来就要计算相交的区间有多少对。首先,相交的区间不可能跨过当前元素,否则就是当前元素作为贡献的区间;所以,相交的区间要么是 \([x,y](l_i\le x\le y<i)\) ,要么是 \([x,y](i<x\le y\le r_i)\)。先计算 \([x,y](l_i\le x\le y<i)\) 与当前元素作为贡献的区间相交的对数,先考虑 \(y\) 固定时,个数为 \((r_i-i+1)\times(y-l_i+1)^2\) ,其中:\(y-l_i+1\) 既是相交的区间左端点的个数,也是与相交的区间相交的当前元素作为贡献的区间的左端点的个数;\(r_i-i+1\) 是与相交的区间相交的当前元素作为贡献的区间的右端点的个数。所以,总数是 \((r_i-i+1)\times\sum\limits_{y=l_i}^{i-1}(y-l_i+1)^2\) ,乘号右边是自然数平方和,可以用公式计算,所以就是 \((r_i-i+1)\times\frac{(i-l_i)\times(i-l_i+1)\times(2i-2l_i+1)}6\) 。\([x,y](i<x\le y\le r_i)\) 同理,总数为 \((i-l_i+1)\times\frac{(r_i-i)\times(r_i-i+1)\times(2r_i-2i+1)}6\) 。
所以,把相交的总对数减掉就可以了。
参考代码:
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int read()
{
int out=0;
char c;
while (!isdigit(c=getchar()));
for (;isdigit(c);c=getchar())
{
out=out*10+c-'0';
}
return out;
}
const int N=200010;
const int M=1000000007;
const int SIX=166666668; //6模1e9+7的逆元
struct Node
{
long long id,w,l,r,t;
bool operator<(const Node& b) const
{
return w<b.w;
}
} a[N];
long long n,suf[N],sta[N],top,ans;
int main()
{
int i;
n=read();
for (i=1;i<=n;++i)
{
a[i].w=read();
a[i].id=i;
}
for (i=1;i<=n;++i)
{
while (top&&a[sta[top]].w>a[i].w)
{
a[sta[top--]].r=i-1;
}
sta[++top]=i;
}
while (top)
{
a[sta[top--]].r=n;
}
for (i=n;i>=1;--i)
{
while (top&&a[sta[top]].w>=a[i].w)
{
a[sta[top--]].l=i+1;
}
sta[++top]=i;
}
while (top)
{
a[sta[top--]].l=1;
}
for (i=1;i<=n;++i)
{
a[i].t=(i-a[i].l+1)*(a[i].r-i+1)%M;
}
sort(a+1,a+n+1);
for (i=n;i>=1;--i)
{
suf[i]=(suf[i+1]+a[i].t)%M;
}
for (i=1;i<=n;++i)
{
ans=(ans+(a[i].w*suf[i+1]%M)*a[i].t)%M;
ans=(ans-(a[i].id-a[i].l)*(a[i].id-a[i].l+1)%M*(2*a[i].id-2*a[i].l+1)%M*SIX%M*(a[i].r-a[i].id+1)%M*a[i].w%M+M)%M; //重复区间在左
ans=(ans-(a[i].r-a[i].id)*(a[i].r-a[i].id+1)%M*(2*a[i].r-2*a[i].id+1)%M*SIX%M*(a[i].id-a[i].l+1)%M*a[i].w%M+M)%M; //重复区间在右
}
cout<<ans;
return 0;
}
WC2019 全国模拟赛第一场 T1 题解的更多相关文章
- NOI.AC省选模拟赛第一场 T1 (树上高斯消元)
link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...
- NOI.AC NOIP模拟赛 第一场 补记
NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- nowcoder(牛客网)提高组模拟赛第一场 解题报告
T1 中位数(二分) 这个题是一个二分(听说是上周atcoder beginner contest的D题???) 我们可以开一个数组b存a,sort然后二分b进行check(从后往前直接遍历check ...
- nowcoder(牛客网)普及组模拟赛第一场 解题报告
蒟蒻我可能考了一场假试 T1 绩点 这题没什么好说的,应该是只要会语言的就会做. T2 巨大的棋盘 一个模拟题吧qwq,但是要注意取模的时候先加上n或者m再取模,要不然会错的. #include< ...
- 【CQ18阶梯赛第一场】题解
[A-风格不统一如何写程序] 输入字符串,得到长度,对于每个字符:如果是大写,则改为:‘_’+小写:如果是‘_’则忽略‘_’,并且把后面的小写改为大写. #include<cstdio> ...
- 2021ICPC网络赛第一场部分题解-The 2021 ICPC Asia Regionals Online Contest (I)
写在前面 本来应该6题的,结果不知道哪个铸币发了H的clar,当即把我们的思路转向三维几何上.当时我们还在想这三维计算几何的正确率有点太高了还在感叹ICPC选手的含金量,直到赛后我才知道这H题的铸币出 ...
- CSP-S全国模拟赛第二场 【nan】
A.count 本场比赛最难的题... 隔板法组合数容斥 xjb 搞搞就好了 //by Judge #include<cstdio> #include<iostream> #d ...
- Contest1585 - 2018-2019赛季多校联合新生训练赛第一场(部分题解)
Contest1585 - 2018-2019赛季多校联合新生训练赛第一场 C 10187 查找特定的合数 D 10188 传话游戏 H 10192 扫雷游戏 C 传送门 题干: 题目描述 自然数中除 ...
随机推荐
- typedef用法和与define的区别
typedef用来声明一个别名,typedef后面的语法,是一个声明.本来笔者以为这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数.罪魁祸首又是那些害人的教材.在这些教材中介绍typed ...
- Spring Cloud Eureka高可用落地实战
一.原理 如图所示,多台Server端之间相互注册(这里以两台Server为例),Client端向所有的Server端注册. 二.Server端配置 1. 添加依赖 <dependency> ...
- vue.js和angular.js的区别
关于Vue的描述: HTML模版+JSON数据,再创建一个Vue实例,就这么简单 关于Angular的描述: AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态 ...
- ps 中添加一张图片
// 测试打开一个文件var fileref = new File ("/E/work/没有图片提交/2014/2014.5.19/G20/部件渲染测试/png/tianji_1-41001 ...
- 455. Assign Cookies
static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...
- SOAP与REST比较(转)
出处:http://xiaobaila.blog.163.com/blog/static/189705129201141965434571/ SOAP与REST比较 如今,Web开发者的可选技术相当之 ...
- 3 Django 简介
MVC 与 MTV 模型 MVC Web 服务器开发领域里著名的 MVC 模式,所谓 MVC 就是把 Web 应用分为模型 (M),控制器(C) 和视图 (V) 三层,他们之间以一种插件式的.松耦合的 ...
- HTTP 499 状态码 nginx下 499错误
日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499.发送字节数是0. 老是有用户反映网站系统时好时坏,因为线上的产 ...
- (广搜) Find a way -- hdu -- 2612
链接: http://acm.hdu.edu.cn/showproblem.php?pid=2612 Find a way Time Limit: 3000/1000 MS (Java/Others) ...
- Cacti部署
1>监控概述 通常运维人员在一个企业当中所需要管理一台或者多台服务器,或者甚至更多,特别是BAT公司或者门户级别的公司,一个人管理的服务器可能上百甚至上千台 ...