天才ACM
给定一个整数m,定义一个集合的权值为从这个集合中任意选出m对数(不够没关系,选到尽可能选,凑不成对的舍去),每对数两个数的差的平方的和的最大值。
现在给出一个数列\(\{a_i\}\),询问最少的区间划分数,让它每个区间的权值不超过p(p已给定),\(1≤n,m≤500000,0≤p≤10^{18}\)
解
首先注意到从集合中选出m对数,让每对数的差的平方的和最大值为一个贪心模型,我们只需要将集合中的元素按从小到大排序,然后把最大数和最小数配对,再将次大数和次小数配对,依次类推即可。
而只要每个区间都尽可能大,那么就是最优方案,于是原问题也就转化为确定了一个左端点,右端点在哪个位置,使权值最大化,不超过p。
法一:二分
考虑二进制优化,于是想到二分,注意到这类似二分模型,比最优方案大就无解,比最优方案小就有解,于是可以考虑二分右端点的位置mid,设二分区间为\([l,r]\),而判断和p的大小关系,就暴力求出二分出来的区间的权值小于p,那么\(l=mid+1\),否则\(r=mid-1\),对于权值如何求,就暴力排序,暴力配对,于是可以做到时间复杂度\(O({\large nlog_2^{n^2}})\)。
事实证明这个算法萎了,但还是给出代码。
参考代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define il inline
#define ri register
#define ll long long
#define Size 500100
using namespace std;
int m,a[Size],b[Size];
template<class free>
il void read(free&);
il ll powsum(int,int);
il int dfs(int,int,int);
int main(){
int lsy;read(lsy);
while(lsy--){
int n,l(1),tot(0);ll T;
read(n),read(m),read(T);
for(int i(1);i<=n;++i)read(a[i]);
while(l<=n)l=dfs(l,n,T),++tot;
printf("%d\n",tot);
}
return 0;
}
il ll powsum(int l,int r){
int i,j,m(::m);ll ans(0);for(i=l;i<=r;++i)b[i]=a[i];sort(b+l,b+r+1);
i=l,j=r;while(i<=j&&m)ans+=(b[i]-b[j])*(b[i]-b[j]),++i,--j,--m;
return ans;
}
il int dfs(int l,int r,int T){
int mid,s(l);
while(l<=r){
mid=l+r>>1;
if(powsum(s,mid)>T)r=mid-1;
else l=mid+1;
}return l;
}
template<class free>
il void read(free &x){
x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
法二:
实际上二进制优化家族中还有倍增,这一有力工具,但要注意思维的开放,如果找老套路从高位开始试填的话,你就会死的与二分一样惨。
不妨声明变量\(l,r,nr,J\),分别表示确定的左端点位置,已经确定的右端点,尝试确定的右端点,一次要往前看的范围为$2^J。
因此每次操作可以这样,先令\(nr=r+2^J\),然后查看区间\([l,nr]\)的权值与p的关系,如果比p大,则只令\(--J\),否则\(r=nr,++J\)。
至于权值怎么办?如果照着老套路,那么又是\(?\)了,根据维护的思想,凭借已有的东西求出未知的东西,我们发现我们已经有了一段序列是有序的,没必要再把整个区间重新排序去检查,我们只需要把因为试填而带出来的新区间进行排序,然后和原来的区间归并,这样就可以做到梦寐以求的\(O(nlogn)\)了。
参考代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define il inline
#define ri register
#define ll long long
#define Size 500050
using namespace std;
int a[Size],b[Size],t[Size];
il ll powsum(int,int,int,int[]);
il void merge(int,int,int,int[]);
template<class free>il void read(free&);
int main(){
int lsy;read(lsy);
while(lsy--){int i,j,tot(0);ll T;
int n,m,l(1),r(1),nr,mj(1);
read(n),read(m),read(T);
for(i=1;i<=n;++i)read(a[i]);b[1]=a[1];
while(r<n){//attention
nr=r+mj;if(nr>n)nr=n;
for(i=r+1;i<=nr;++i)b[i]=a[i];
sort(b+r+1,b+nr+1),merge(l,r,nr,b);
if(powsum(l,nr,m,t)>T)mj>>=1;
else{
r=nr,mj<<=1;
for(i=l;i<=r;++i)b[i]=t[i];
}
if(!mj)l=r+1,mj=1,++tot;
}printf("%d\n",tot+1);
}
return 0;
}
il ll powsum(int l,int r,int m,int a[]){ll ans(0);
while(l<=r&&m)ans+=(ll)(a[r]-a[l])*(a[r]-a[l]),++l,--r,--m;
return ans;
}
il void merge(int l,int mid,int r,int a[]){
int i(l),j(mid+1),k(l);
while(i<=mid&&j<=r)
if(a[i]<a[j])t[k++]=a[i++];
else t[k++]=a[j++];
while(i<=mid)t[k++]=a[i++];
while(j<=r)t[k++]=a[j++];
}
template<class free>
il void read(free &x){
x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
天才ACM的更多相关文章
- AcWing:109. 天才ACM(倍增 + 归并排序)
给定一个整数 MM,对于任意一个整数集合 SS,定义“校验值”如下: 从集合 SS 中取出 MM 对数(即 2∗M2∗M 个数,不能重复使用集合中的数,如果 SS 中的整数不够 MM 对,则取到不能取 ...
- (暂时弃坑)(半成品)ACM数论之旅18---反演定理 第二回 Mobius反演(莫比乌斯反演)((づ ̄3 ̄)づ天才第一步,雀。。。。)
莫比乌斯反演也是反演定理的一种 既然我们已经学了二项式反演定理 那莫比乌斯反演定理与二项式反演定理一样,不求甚解,只求会用 莫比乌斯反演长下面这个样子(=・ω・=) d|n,表示n能够整除d,也就是d ...
- 【转载】ACM总结
转自亲学长的总结 声明:本文是写给弱校ACM新手的一点总结,受自身水平和眼界所限,难免会有一些个人主观色彩,希望大牛指正 感谢@Wackysoft .@哇晴天 . @ 一切皆有可能1 的指教,现根据这 ...
- ACM/ICPC 之 BFS(离线)+康拓展开(TSH OJ-玩具(Toy))
祝大家新年快乐,相信在新的一年里一定有我们自己的梦! 这是一个简化的魔板问题,只需输出步骤即可. 玩具(Toy) 描述 ZC神最擅长逻辑推理,一日,他给大家讲述起自己儿时的数字玩具. 该玩具酷似魔方, ...
- ACM感悟
声明:本文是写给弱校ACM新手的一点总结,受自身水平和眼界所限,难免会有一些个人主观色彩,希望大牛指正 感谢@Wackysoft .@哇晴天 . @ 一切皆有可能1 的指教,现根据这些建议,文章已进行 ...
- 一位ACM过来人的心得(转)
励志下! 刻苦的训练我打算最后稍微提一下.主要说后者:什么是有效地训练? 我想说下我的理解.很多ACMer入门的时候,都被告知:要多做题,做个500多道就变牛了.其实,这既不是充分条件.也不会是必要条 ...
- ACM生活总结
两年ACM生活总结 转眼已经踏入ACM这条不归路已经两年了, 深深的感觉到ACM的不易 和 艰辛,但同时ACM给我所带来的快乐,让我认为值一切都是值得的. 我刚上大学那会,我们学校的ACM刚刚起步不到 ...
- 一位ACM过来人的心得
刻苦的训练我打算最后稍微提一下.主要说后者:什么是有效地训练? 我想说下我的理解. 很多ACMer入门的时候,都被告知:要多做题,做个500多道就变牛了.其实,这既不是充分条件.也不会是必要条件. 我 ...
- 关于ACM,关于CSU
原文地址:http://tieba.baidu.com/p/2432943599 前言: 即将进入研二,ACM的事情也渐渐远去,记忆终将模糊,但那段奋斗永远让人热血沸腾.开个贴讲讲ACM与中南的故事, ...
随机推荐
- GCloud SDK 遇到的错误记录
eclipse 环境 1.调用 SetAppInfo 方法返回 -1 语音id 和 key 设置正确 ,各种检测都没问题 解决办法 把安卓工程目录下 obj 文件价删除 ,把sdk 替换成以前能用的老 ...
- Java处理图片工具类
import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.awt.Graphic ...
- Java HashSet和ArrayList的查找Contains()时间复杂度
今天在刷leetCode时,碰到了一个题是这样的. 给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 看到 ...
- 使用 SpringBoot 配置发送邮件功能
1.使用 SpringBoot 配置发送邮件功能 项目总体结构 用户表设计 SET FOREIGN_KEY_CHECKS=0; CREATE DATABASE sample; USE sample; ...
- jenkins的安装和启用
1.下载Jenkins:下载地址:https://jenkins.io/zh/download/ 2.将Jenkins.war包上传到Tomcat的webapps目录下,本次的目录是/usr/loca ...
- 【JZOJ6411】上网
description analysis 如果把所有大小关系连成边,小的往大的连,就可以直接上拓扑 暴力连边时间复杂度\(O(n^2)\),然而连边的过程,考虑用线段树优化 线段树上的所有儿子节点向父 ...
- 使用multiprocessing模块创建进程
#_author:来童星#date:2019/12/17from multiprocessing import Processimport timeimport os#两个子进程将会调用的两个方法de ...
- 依赖背包变形——hdu4003
思维性比较强,代码挺简单的,dp[u][j]表示在u子树下安排j个机器人,让其不回u 注意转移时的初始值 /* dp[u][j]为在子树u有j个机器人不回来 */ #include<bits/s ...
- NOIp2018集训test-9-18
T1.Conjugate 只能选没选过的点,看成如果选了选过的堆的点就不管它继续选.如果第一次选到某一堆的点在第一次选到第一堆的点之前,这一堆对答案就会有1的贡献.那么a[i]有贡献的概率是a[i]和 ...
- NX二次开发-C++的vector排序去重用法
#include <algorithm> //vector排序去重 sort( BoxNum.begin(), BoxNum.end()); BoxNum.erase(unique(Box ...