源: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 统计数对的更多相关文章

  1. Cheatsheet: 2015 10.01 ~ 10.31

    .NET Publishing your ASP.NET App to Linux in 5 minutes with Docker Integrating AngularJS with ASP.NE ...

  2. Cheatsheet: 2015 06.01 ~ 06.30

    Web The Front-End Optimization Checklist [ASP.NET 5] Production Ready Web Server on Linux. Kestrel + ...

  3. Murano Weekly Meeting 2015.12.01

    Meeting time: 2015.December.1st 1:00~2:00 Chairperson:  Nikolay Starodubtsev, from Mirantis Meeting ...

  4. Murano Weekly Meeting 2015.09.01

    Meeting time: 2015.September.1st 1:00~2:00 Chairperson:  Nikolay Starodubtsev, from Mirantis Meeting ...

  5. 使用jquery脚本获取随笔、文章和评论的统计数,自定义显示位置

    为了这个问题,花了好些时间去摸索,无奈没有搞定.于是,我就到博问去提问,终于搞定! 在此,非常感谢SeayXu的热心帮助. 1.在需要的位置添加一个标签 <div id="stats_ ...

  6. Archlinux 2015.07.01 和 Windows7 双系统 安装教程

    提前在windows7下给Archlinux预留一个分区,大小最好在20G以上(根据自己硬盘情况分配). 第一步,安装前的准备 从arch官网下载最新的ISO文件archlinux-2015.07.0 ...

  7. Cheatsheet: 2015 12.01 ~ 12.31

    Mobile Setting Up the Development Environment iOS From Scratch With Swift: How to Test an iOS Applic ...

  8. Cheatsheet: 2015 11.01 ~ 11.30

    Golang Roadomatic: Node vs. Go Quick Guide to Golang for Java Developers 3 Go Gotchas Web Choosing a ...

  9. Cheatsheet: 2015 09.01 ~ 09.30

    Web A Guide to Vanilla Ajax Without jQuery Gulp for Beginners A Detailed Walkthrough of ASP.net MVC ...

随机推荐

  1. VS 创建 使用C++ 静态类库(Dll)

    创建静态类库 Walkthrough: Creating and Using a Dynamic Link Library (C++) 1:菜单栏-->File, New, Project. 2 ...

  2. 关于XML(一)。

    关于XML 什么是XML? XML是可扩展标记语言.类似于HTML,XML的宗旨是旨在传输数据,而非显示数据.其标签没有预定义,您需要自行定义标签.XML具有自我描述性,是W3C的推荐标准. XML与 ...

  3. VS2010 Cstring to int

    今天遇到一个将Cstring转化为int的问题,用atoi(),发现不可以,找了一下原因. 原来因为在VS2015(2010)的版本中是UNICODE ,请使用这个函数 _ttoi() . CStri ...

  4. 从 man 指令起步(info简介)

    前言 小生认为一切指令的学习首先要从帮助入手,深入了解它的功能,即使是在实际项目中我们都离不开它的帮助.因为我们不一定能够记住全部指令的全部的相关功能,因此,查看指令的帮助是我们的不二选择. 正文 下 ...

  5. Windows7 IIS7 无法启动计算机上的服务W3SVC如何修复

    错误提示 启动iis7管理服务器提示:无法启动计算机上的服务W3SVC 启动Windows Process Activation Service服务,报错:6801 指定资源管理器中的事务支持未启动或 ...

  6. springMVC整合memcached,以注解形式使用

    睡不着,深夜写点博客.闲下来有一个月了,心里多少有点…… 在北京找工作一再受阻,这个时间点也不好找 再接再厉 之前没有用过memcached,没有什么实战经验,看了一些关于memcached的博客,写 ...

  7. PHP 关于MongoDB的操作

    <?php header("Content-type:text/html;charset=utf-8"); $m = new MongoClient(); // 连接 $db ...

  8. 小记搭建WAPM运行ThinkPHP时所需要的配置

    最近因为项目而接触到了Thinkphp,正在上手中.但昨天遇到几个问题,一下子牵连出之前搭建WAPM(windows+apache+PHP+MySQL)遗留的配置问题. aphache\conf目录下 ...

  9. TatukGIS - GisDefs - ColorToHSL 过程

    过程名称  ColorToHSL 所在单元  GisDefs 过程原型           procedure ColorToHSL(const _color: TColor; var _h: Rea ...

  10. 舵机的PWM控制学习随笔

    舵机的控制信号,对于脉宽调制信号的脉宽变换,常用的一种方法是采用调制信号获取有源滤波后的直流电压,但是需要50Hz(周期是20ms)的信号,这对运放器件的选择有较高要求,从电路体积和功耗考虑也不易采用 ...