洛谷 P6006 [USACO20JAN]Farmer John Solves 3SUM G
洛谷 P6006 [USACO20JAN]Farmer John Solves 3SUM G
Problem
什么是3-SUM?
给你一个序列\(a\),求有多少组\((i,j,k)(1\le i<j<k\le n)\)满足\(a_i+a_j+a_k=0\).
这是一个有名的算法问题,尚未发现比运行速度比平方时间明显更优的解法。
这道题给你一个长度为\(n(n\le5000)\)的序列,之后有\(q(q\le10^6)\)个询问,查询你区间\([l,r]\)的\(3-SUM\)的答案。
Solution
当你看到题目描述的时候,可能会想那位Farmer John的重大突破是啥。但是你只要知道怎么\(O(n^2)\),再想想这个\(O(n^2)\)能不能预处理,然后用更低的时间复杂度查询就好。(别以为真的有啥接近线性的算法)
首先怎么\(O(n^2)\)做呢?
枚举两个变量,对当前的第三个变量的能取的范围预先开好一个桶计数。这样我们就固定了两个变量\(i,j\),去桶里面找\(-a_i-a_j\)的数量即可。
如果你是枚举\(i,j\),对k的取值范围\([j+1,n]\)开桶的话,当然也可以但是这个k的限制并不显然(或者是也有向下做的方法只是我没有想到吧)
如果我们枚举\(i,k\),这样\(k\)的取值范围就是\([i+1,k-1]\)。记\(c_x\)表示在当前区间内,等于\(x\)的\(a_k\)的数量;设\(f_{i,k}\)表示选定左端点为\(i\),右端点为\(k\)时的3-SUM方案数。
for(int i=1;i<=n;i++)
{
c[a[i+1]+M]++;
for(int k=i+2;k<=n;k++)
{
if(a[i]+a[k]<=M&&a[i]+a[k]>=-M) f[i][k]+=c[M-a[i]-a[k]];
c[a[k]+M]++;
}
c[a[i+1]+M]--;
for(int k=i+2;k<=n;k++)
{
c[a[k]+M]--;//clear
}
}
代码中的c是桶,M可以先不管(见下文)
对于一个询问\((l,r)\),这里的\(i,k\)当然可以选\([l,r]\)中的任意值(只要满足\(i<k\))。这不就是求
\]
这部分可以用二维前缀和预处理出来。
这样对于每一个询问都可以\(O(1)\)回答了。
需要注意的地方
不需要在求二维前缀和的时候判断\(i<k\)(准确说是\(i<\dots<k\Rightarrow i+1<k\)),因为不合法部分的\(f_{i,k}\)依然是\(0\).
即直接预处理
\]
对于每个询问用二维前缀和的差分
\]
就好了。
以及注意值域有负数,所以桶的大小要开两倍并且给所有的数都加上一个\(10^6\)。
Code
/**************************************************************
* Problem: 6006
* Author: Vanilla_chan
* Date: 20210307
**************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
#ifdef ONLINE_JUDGE
char buf[1<<23],* p1=buf,* p2=buf,obuf[1<<23],* O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
using namespace std;
template<class T>inline void read(T& x)
{
char ch=getchar();
int fu;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)) { x=x*10+ch-'0';ch=getchar(); }
x*=fu;
}
inline int read()
{
int x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)) { x=x*10+ch-'0';ch=getchar(); }
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do { G[++g]=x%10;x/=10; } while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
#define N 6010
int n,q;
int a[N];
LL f[N][N];
int c[2000010];
#define M 1000000
int main()
{
n=read();
q=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
{
c[a[i+1]+M]++;
for(int k=i+2;k<=n;k++)
{
if(a[i]+a[k]<=M&&a[i]+a[k]>=-M) f[i][k]+=c[M-a[i]-a[k]];
c[a[k]+M]++;
}
c[a[i+1]+M]--;
for(int k=i+2;k<=n;k++)
{
c[a[k]+M]--;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
}
int x,y;
while(q--)
{
x=read();
y=read();
if(x>y) swap(x,y);
write(f[y][y]-f[x-1][y]-f[y][x-1]+f[x-1][x-1]);
}
return 0;
}
洛谷 P6006 [USACO20JAN]Farmer John Solves 3SUM G的更多相关文章
- 洛谷 P2882 [USACO07MAR]Face The Right Way G
题目传送门 题目描述 Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing ...
- 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码
洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ...
- 洛谷 P1596 [USACO10OCT]湖计数Lake Counting
题目链接 https://www.luogu.org/problemnew/show/P1596 题目描述 Due to recent rains, water has pooled in vario ...
- 洛谷 [USACO17OPEN]Bovine Genomics G奶牛基因组(金) ———— 1道骗人的二分+trie树(其实是差分算法)
题目 :Bovine Genomics G奶牛基因组 传送门: 洛谷P3667 题目描述 Farmer John owns NN cows with spots and NN cows without ...
- 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)
To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows con ...
- 洛谷 1938 [USACO09NOV]找工就业Job Hunt
洛谷 1938 [USACO09NOV]找工就业Job Hunt 题目描述 Bessie is running out of money and is searching for jobs. Far ...
- 洛谷 2953 [USACO09OPEN]牛的数字游戏Cow Digit Game
洛谷 2953 [USACO09OPEN]牛的数字游戏Cow Digit Game 题目描述 Bessie is playing a number game against Farmer John, ...
- 【洛谷】P2880 [USACO07JAN]平衡的阵容Balanced Lineup(st表)
题目背景 题目描述: 每天,农夫 John 的N(1 <= N <= 50,000)头牛总是按同一序列排队. 有一天, John 决定让一些牛们玩一场飞盘比赛. 他准备找一群在对列中为置连 ...
- 洛谷 P3659 [USACO17FEB]Why Did the Cow Cross the Road I G
//神题目(题目一开始就理解错了)... 题目描述 Why did the cow cross the road? Well, one reason is that Farmer John's far ...
- [洛谷P2852] [USACO06DEC]牛奶模式Milk Patterns
洛谷题目链接:[USACO06DEC]牛奶模式Milk Patterns 题目描述 Farmer John has noticed that the quality of milk given by ...
随机推荐
- @SpringBootApplication自动配置原理
@EnableAutoConfiguration 是核心,他会调用一个@Import注解.我们已知Import自动配置得实现是通过创建ImportSelector 接口的实现类并重写里面selectI ...
- VirtualBox磁盘扩容
前言 虚拟机开始时设置的磁盘空间比较小,后面使用就不够了. # 查询磁盘使用情况 df -h 虚拟硬盘扩容 关闭正在运行的虚拟机 选中工具栏 选择虚拟硬盘,并选中需要扩容的磁盘 拖动进度条,设置想要扩 ...
- windows linux子系统(Ubuntu)ip地址
在Windows10安装好了的子系统(Ubuntu)上,安装了nginx 想去访问,使用ipconfig .ip add,查询来的ip地址都跟自己Windows10的ip完全一样,难道Linux子系统 ...
- php处理跨域
1.允许所有域名访问 header('Access-Control-Allow-Origin: *'); 2.允许单个域名访问 header('Access-Control-Allow-Origin: ...
- Sql 字符串截取
注意 不同数据库内置函数名称或有差异,可参考 1.从左至右截取 ①使用left()函数可以从左至右对字符串进行截取 语法:LEFT(str,length) str是要进行截取的字符串,length是要 ...
- Tomcat之Jconsole监控
JConsole的图形用户界面是一个符合Java管理扩展(JMX)规范的监测工具,JConsole使用Java虚拟机(Java VM),提供在Java平台上运行的应用程序的性能和资源消耗的信息.在Ja ...
- C# - 获取枚举描述 - 使用增量源生成器
前言 C# 获取枚举描述的方法有很多, 常用的有通过 DescriptionAttribute 反射获取, 进阶的可以加上缓存机制, 减少反射的开销.今天我们还提供一种更加高效的方法,通过增量源生成器 ...
- DRG,医改分水岭!
2020-11-04 (2021年政府推出2.0版DRG.增加MCC和CC,各自政府的医保支付中增加了人性化的支付倍率的处理) 假设某疾病病组支付标准10000元,患者自付自费比例40%,分三种情况, ...
- EditorGUILayout.BeginVertical("textfield")
- rabbitmq防止消息的重复消费
一.rabbitmq出现消息重复的场景 A:消息消费成功,事务已经提交,ack时,机器宕机,导致没有ack成功, Broker的消息重新由unack变为ready,并发送给其他消费者 B:消息消费失败 ...