2015 CCC - 01 统计数对
源:CNUOJ-0384 http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=354
题目分析:当时拿到这道题第一个想法就是排序后n^2暴力枚举,充分利用好有序这一特性随时“短路”。
read(n);read(m);
int temp; for(int i = ; i < n; i++)
{
read(temp);
if(temp <= m)
{
p[tot].v = temp;
p[tot++].num = i;
}
} sort(p, p + tot); for(int i = ; i < tot - ; i++)
{
for(int j = i + ; j < tot; j++)
{
if(p[i].v + p[j].v > m) break;
else if(p[i].num < p[j].num) ans++;
}
ans %= ;
} printf("%d\n", ans); return ;
算法1
然后很高兴的简单一测试就哭了……为什么答案始终不对呢……
如上图就是一个十分典型的例子(下标为序号),不难发现当我们手算时,我们是算的“2 + 1”,但排完序后计算机执行的是“1 + 2”,序号不符合题意就被砍掉了……
那么怎么解决呢?第一个想法便是优化一下 j 的循环,从头到尾全来一遍,保证不漏解:
read(n);read(m);
int temp; for(int i = ; i < n; i++)
{
read(temp);
if(temp <= m)
{
p[tot].v = temp;
p[tot++].num = i;
}
} sort(p, p + tot); for(int i = ; i < tot; i++)
{
for(int j = ; j < tot; j++)
{
if(i == j) continue;
if(p[i].v + p[j].v > m) break;
else if(p[i].num < p[j].num) ans++;
}
ans %= ;
} printf("%d\n", ans);
算法2
排序是nlogn,枚举是n^2,对于十万的数据量无法吐槽……只能有50分……
好的,接下来我们来分析一下这个算法干了些什么,比如对于3 2 1这个序列:
可以看到,1 -> 2, 2 -> 1 分别别计算过一次,其中红色的一次失败了,蓝色的成功了。(在红色中3 > 2,而在蓝色中是2 < 3满足题意)
也不难得出:每一对数字都被正着计算了一次,反着计算了一次;一次失败,一次成功。
那么:反正判断不判断都是ans++ 一次(仅成功一次,失败的时候不会更新),那为什么要判断呢?
于是,我们编出了下面没有判断编号只判断了大小的程序:
for(int i = ; i < tot - ; i++)
{
for(int j = i + ; j < tot; j++)
{
if(p[i].v + p[j].v > m) break;
ans++;
}
ans %= ;
}
算法3
这个算法常数可以几乎砍掉一半多,但复杂度仍然是n^2的,它的表现……呵呵
进一步的优化就要从查询方法开始了:用十分常见的二分法效果怎么样呢?于是我们终于得到了标程:
#include <iostream> //第一题标程
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std; const int maxn = + ;
int n, m; int p[maxn];
int ans = ; int tot = ; int A[maxn]; void read(int& x)
{
x = ;
char ch = getchar();
int sig = ;
while(!isdigit(ch))
{
if(ch == '-') sig = -;
ch = getchar();
}
while(isdigit(ch))
{
x = x * + ch - '';
ch = getchar();
}
x *= sig;
return ;
} int main()
{
read(n);read(m);
int temp; for(int i = ; i < n; i++)
{
read(temp);
if(temp <= m) p[tot++] = temp;
} sort(p, p + tot); int L, R, M; for(int i = ; i < tot - ; i++)
{
L = i;
R = tot - ; if(p[R] + p[i] <= m)
{
ans += R - i;
continue;
} while(L < R)
{
M = L + R >> ;
//printf("L:%d M:%d R:%d\n", L, M, R);
if(p[i] + p[M] <= m) L = M + ;
else R = M;
} if(L - i > ) ans += L - i - ; //cout << ans << endl;
ans %= ;
} printf("%d\n", ans); return ;
}
从n^2到nlogn是不小的进步,十万的数据专为nlogn而生:
这道题就这样被干掉了……
当然了,其实还可以用treap瞎搞啦:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;
const int maxn = + ;
struct Node{
int r, v, s;
Node* ch[];
Node() {}
void maintain(){
s = ch[] -> s + ch[] -> s + ;
return ;
}
}nodes[maxn], *null = &nodes[];
int tot = , n, m, A[maxn];
void read(int& x){
x = ; int sig = ; char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') sig = -; ch = getchar(); }
while(isdigit(ch)) x = * x + ch - '', ch = getchar();
x *= sig; return ;
}
void rotate(Node* &o, int d){
Node* k = o -> ch[d ^ ];
o -> ch[d ^ ] = k -> ch[d];
k -> ch[d] = o;
o -> maintain();
k -> maintain();
o = k;
return ;
}
void init(Node* &o, int v){
o -> ch[] = null;
o -> ch[] = null;
o -> s = ;
o -> r = rand();
o -> v = v;
return ;
}
void insert(Node* &o, int v){
if(o == null){
o = &nodes[++ tot];
init(o, v);
}
else{
int d = v < o -> v ? : ;
insert(o -> ch[d], v); //你大爷
if(o -> ch[d] -> r > o -> r) rotate(o, d ^ );
}
o -> maintain();
return ;
}
void remove(Node* &o, int v){
if(o == null) return ;
if(o -> v == v){
if(o -> ch[] == null) o = o -> ch[];
else if(o -> ch[] == null) o = o -> ch[];
else{
int d = o -> ch[] -> r < o -> ch[] -> r ? : ;
rotate(o, d);
remove(o -> ch[d ^ ], v);
}
}
if(o != null) o -> maintain();
return ;
}
/*int find(Node* &o, int v){
if(o == null) return -1;
if(o -> v == v){
if(o -> ch[0] != null) return o -> ch[0] -> s;
else return 1;
}
int d = v < o -> v ? 0 : 1;
return find(o -> ch[d], v);
}//*/
int rank(Node* &o, int v){
if(o == null) return ;
if(o -> v > v) return rank(o -> ch[], v);
else return rank(o -> ch[], v) + o -> ch[] -> s + ;
}
Node* root = null;
long long ans = ;
void Init(){
srand(time());
null -> s = ;
read(n); read(m);
for(int i = ; i < n; i ++){
read(A[i]);
ans += rank(root, m - A[i]);
//printf("%d ", rank(root, m - A[i]));
insert(root, A[i]);
}
return ;
} void print(Node* &o){
if(o == null) return ;
print(o -> ch[]);
printf("%d ", o -> v);
print(o -> ch[]);
return ;
} int main(){
Init();
printf("%lld\n", ans % );
return ;
}
/*
5 100000
1 2 3 4 5
*/
小结:本题一定要好好读条件,仔细分析哪些可以优化。
考点:二分,坑题
2015 CCC - 01 统计数对的更多相关文章
- Cheatsheet: 2015 10.01 ~ 10.31
.NET Publishing your ASP.NET App to Linux in 5 minutes with Docker Integrating AngularJS with ASP.NE ...
- Cheatsheet: 2015 06.01 ~ 06.30
Web The Front-End Optimization Checklist [ASP.NET 5] Production Ready Web Server on Linux. Kestrel + ...
- Murano Weekly Meeting 2015.12.01
Meeting time: 2015.December.1st 1:00~2:00 Chairperson: Nikolay Starodubtsev, from Mirantis Meeting ...
- Murano Weekly Meeting 2015.09.01
Meeting time: 2015.September.1st 1:00~2:00 Chairperson: Nikolay Starodubtsev, from Mirantis Meeting ...
- 使用jquery脚本获取随笔、文章和评论的统计数,自定义显示位置
为了这个问题,花了好些时间去摸索,无奈没有搞定.于是,我就到博问去提问,终于搞定! 在此,非常感谢SeayXu的热心帮助. 1.在需要的位置添加一个标签 <div id="stats_ ...
- Archlinux 2015.07.01 和 Windows7 双系统 安装教程
提前在windows7下给Archlinux预留一个分区,大小最好在20G以上(根据自己硬盘情况分配). 第一步,安装前的准备 从arch官网下载最新的ISO文件archlinux-2015.07.0 ...
- Cheatsheet: 2015 12.01 ~ 12.31
Mobile Setting Up the Development Environment iOS From Scratch With Swift: How to Test an iOS Applic ...
- Cheatsheet: 2015 11.01 ~ 11.30
Golang Roadomatic: Node vs. Go Quick Guide to Golang for Java Developers 3 Go Gotchas Web Choosing a ...
- Cheatsheet: 2015 09.01 ~ 09.30
Web A Guide to Vanilla Ajax Without jQuery Gulp for Beginners A Detailed Walkthrough of ASP.net MVC ...
随机推荐
- css 权威指南笔记(一)
零零散散接触css将近5年,俨然已经成为一个熟练工.如果不是换份工作,我不知道自己差的那么远:在qunar的转正review中我这种“知其然而不知其所以然” 的状况被标明,我才意识到我已停步不前近两年 ...
- 利用jpedal进行pdf转换成jpeg,jpg,png,tiff,tif等格式的图片
项目中运用到pdf文件转换成image图片,开始时使用pdfbox开源库进行图片转换,但是转换出来的文件中含有部分乱码的情况.下面是pdfBox 的pdf转换图片的代码示例. try{ String ...
- 记一次网站服务器迁移(my)
遇到的难题: 基本没有遇到太大的问题,因为服务器环境是配好的阿里云环境,最后再nginx的rewrite配置遇到了一点问题,最后也算解决. 收获小点: 1) vim替换命令: 利用 :s 命令可以实现 ...
- OpenWrt的主Makefile工作过程
OpenWrt是一个典型的嵌入式Linux工程,了解OpenWrt的Makefile的工作过程对提高嵌入式Linux工程的开发能力有极其重要意义. OpenWrt的主Makefile文件只有100行, ...
- oracle 中查看一张表是否有主键,主键在哪个字段上的语句怎么查如要查aa表,
select a.constraint_name, a.column_name from user_cons_columns a, user_constraints b where a.constra ...
- Objective-C中的分类与协议
分类 在谈分类之前,我们可以先探究下,OC中为什么出现分类这种机制,有什么好处? 假设你接到一个大项目:计算两个整数的和,差.接到任务的你马上动手.编写代码如下: #import <Founda ...
- 判断PHP数组是否为空的代码
PHP判断数组为空首选方法:count($arr),size($arr); 复制代码 代码如下: $arr= array(""); echo count($arr); echo s ...
- C# 多线程、结构体
struct IpAndPort { public string Ip; public int Port; } private void Form1_Load(object sender, Event ...
- php利用smtp类轻松的发送电子邮件
当你还在纠结php内置的mail()函数不能发送邮件时,那么你现在很幸运,此时的这篇文章可以帮助到你! php利用smtp类来发邮件真是屡试不爽,我用过很久了,基本上没出过问题.本博客后台,当博主回复 ...
- Java学习----集合框架总结
集合框架总结: Collection接口: Set接口: HashSet//对象必须实现hashCode方法,元素没有顺序呢,效率比LinkedHashSet高 LinkedHashSet//是Has ...