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 ...
随机推荐
- linux mysql命令
一: 1.启动 MySQL安装完成后启动文件mysql在/etc/init.d目录下,在需要启动时运行下面命令即可. /etc/init.d/mysql start 2.停止 /usr/bin/mys ...
- 首页在linux下的哪个文件夹
/data/mindo/tomcat-live/webapps/ROOT/WEB-INF/templates/default/pages/index.jsp svn检出地址 https://sif ...
- css 权威指南笔记( 五)结构和层叠
特殊性 重要性 !important; 继承 向上传播例外,应用到body元素的背景样式可以传递到html元素,相应对的可以定义其画布. 大多数框模型属性(包括外边距.内边距.背景.边框)都不能继承 ...
- Codeforces 552E - Vanya and Brackets【表达式求值】
给一个只有加号和乘号的表达式,要求添加一对括号使得最后结果最大.表达式长度5000,乘号最多12个,表达式中数字只有1位. 左括号一定在乘号右边,右括号一定在乘号左边,因为如果不是这样的话,一定可以调 ...
- iOS socket编程
// // ViewController.m // socket // // Created by emerys on 16/3/2. // Copyright © 2016年 Emerys. All ...
- QWidget QMainWindow QDialog 三者区别
Qt类是一个提供所需的像全局变量一样的大量不同的标识符的命名空间.通常情况下,你可以忽略这个类.QObject和一些其它类继承了它,所以在这个Qt命名空间中定义的所有标识符通常情况下都可以无限制的使用 ...
- Mac OS X 系统下快速显示隐藏文件的方法(使用Automator创建workflow)
有的时候需要显系统中的隐藏文件,在 Mac 中不像windows系统那么方便(勾选选项就能够操作),需要在 Terminal 中执行: localhost:~ mx$ defaults write c ...
- 『重构--改善既有代码的设计』读书笔记----Move Method
明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...
- html 中 #include file 的用法
有两个文件a.htm和b.htm,在同一目录下a.htm内容如下 <!-- #include file="b.htm" --> b.htm内容如下 今天:雨 31 ℃- ...
- H5中需要掌握的 ANIMATION 动画效果
CSS3的动画在PC网页上或者APP上用得越来越多,比如H5页面的应用,目前在营销传播上的意义比较大,还有企业官网或者APP主要介绍也用得比较多,当然还有很多地方都用到.所以学习css的动画也迫在眉睫 ...