题意

f(u,v):x小于等于u且y小于等于v的点才对f有贡献,每个这样的点贡献(u-x)+()

思路

=f(u_2,v_2)" class="mathcode" src="https://private.codecogs.com/gif.latex?u_1%20%5Cge%20u_2%20%5C%3B%20and%20%5C%3B%20v_1%20%5Cge%20v_2%20%5Cquad%20%5CRightarrow%20%5Cquad%20f%28u_1%2Cv_1%29%3E%3Df%28u_2%2Cv_2%29">

且等号当且仅当时取。

因此对于输入的0)" class="mathcode" src="https://private.codecogs.com/gif.latex?C%28C%3E0%29">,对于1个特定的,至多有一个似的. (标号①)

当我们固定一个变量的时候,关于另一个变量是单调的(标号②)

因此,我选择横竖两条线移动。

初始状态u=0,v=N.此时f值显然过小。

对于一个状态,

如果f过小,则只能往竖线右调,f才可能增大。

如果f过大,则只能横线往下调。

如果f刚好,答案计数加1,同时,这个u已经不可能有v符合了。往右调(其实往下调也行,关键是要固定一种走法)。

f过小时,v往上调是没有意义的,因为初始状态是v所能取的最大值(N),能到达目前的状态,是从前面的太大或者已经计数过的答案状态转移过来的。往上调就是是走回头路,回去要不就是f过大,要不就是已经计数了的恰好等于f的状态。

同理,f过大时,竖线左调是没有意义的。

同时根据(标号①)的结论易证,不会有情况疏漏掉。

换句话说,如此移动,不重不漏,至多移动2N次。

具体可以参考C++源码

注意,getCount不要用二分,直接枚举就好了。

二分反而会更慢,慢原因是二分需要先排序,排序是,是排序数组片段长度。

而注意到getCount(u,v)每一个u至多查询1次,直接枚举是,反而复杂度更低。

复杂度估计,由于每个片段至多查询一次,且最坏情况下所有片段都查询了。因此对于一个输入C,总的复杂度是.

有个2倍是因为对反过来的rp也要考虑。

因此总复杂度是

不考虑系数,大概带入数字算一下。不超过20*10*10^5+(1000-20)*10*10^4=1.18*10^8.

4s时间限制是OK的。

源码

java(Tle)

java一开始我的java jdk时1.8.ZOJ评测时1.7.莫名RE

后来用1.7,还是莫名RE.

最后故意加死循环,提交。二分测试发现ZOJ Java switch不支持枚举型变量。黑人问号。

最后无奈改成if语句,然后从Re变成Tle了。根据网上的进行了输入输出优化还是不行。

import java.util.*;
import java.io.*;
public class Main {
static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) {
try {
cin.nextToken();
int cnt = (int) cin.nval;
LittleSubAndHisGeometryProblem p;
for (int i = 0;i < cnt; ++i) {
p = new LittleSubAndHisGeometryProblem();
p.run();
}
cout.flush();
} catch (Exception e) { }
}
} class LittleSubAndHisGeometryProblem{
final int N;
int pointCnt;
PointsSys normal;
PointsSys reverse;
int queryCnt; LittleSubAndHisGeometryProblem() throws Exception { Main.cin.nextToken();
N = (int)Main.cin.nval; Main.cin.nextToken(); pointCnt = (int)Main.cin.nval; // 做准备工作,方便满足“a=a0,b<=b0的点的个数及他们的b之和”
normal = new PointsSys();
reverse = new PointsSys();
int x,y;
for (int i = 0;i < pointCnt; ++i) {
Main.cin.nextToken();
x = (int)Main.cin.nval;
Main.cin.nextToken();
y = (int)Main.cin.nval;
normal.add(x,y);
reverse.add(y,x);
} Main.cin.nextToken();
queryCnt = (int)Main.cin.nval;
} class PointSysQueryInfo{
int cnt = 0;
long sum = 0;
void add(long a) {
++cnt;
sum += a;
}
} class PointsSys{
int cnt;
ArrayList<ArrayList<Integer>> p; PointsSys() {
p = new ArrayList<ArrayList<Integer>>();
for (int i = 0;i <= N; ++i)
p.add(new ArrayList<Integer>());
} void add(int x,int y) {
p.get(x).add(y);
} void query(int x,int y,PointSysQueryInfo change) {
// 返回X值恰好为x,且Y值小于等于y的所有点的信息
// 返回点数和sigama(y-Yi) Yi取遍所有的满足要求的点的Y
change.cnt = 0;
change.sum = 0;
ArrayList<Integer> list = p.get(x);
for (int Y : list)
if (Y <= y)
change.add(y-Y);
}
} public enum Move{
Right,Down
} void count() {
// 求解符合题意的方案数
queryAns = 0;
if (2L*N*pointCnt <= c)
return;
int u = 0;
int v = N;
PointSysQueryInfo curr = new PointSysQueryInfo();
PointSysQueryInfo change = new PointSysQueryInfo();
Move moveFlag = Move.Right;
//boolean first = true;
while (u <= N && v > 0) {
if (curr.sum == c)
++queryAns;
if (moveFlag == Move.Right) { // Go Right
++u;
if (u > N) return;
normal.query(u, v ,change);
curr.sum += change.sum + curr.cnt;
curr.cnt += change.cnt;
} else { // Go Down
if (v <= 0) return;
reverse.query(v,u,change);
--v;
curr.cnt -= change.cnt;
curr.sum -= change.sum+curr.cnt;
}
if (curr.sum >= c)
moveFlag = Move.Down;
else
moveFlag = Move.Right;
}
return;
} long c;
int queryAns;
void run() throws Exception {
boolean first = true; for (int i = 0; i < queryCnt; ++i) { Main.cin.nextToken();
c = (long)Main.cin.nval; count();
if (first) {
Main.cout.print(queryAns);
first = false;
} else {
Main.cout.print(" "+queryAns);
}
}
Main.cout.println();
}
}

C++ (AC)

#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 100005;
int N,K;
vector<int>p[kMaxN];
vector<int>rp[kMaxN]; void getCount(vector<int>&p,int b,int &cnt,long long &s) {
cnt = 0;
s = 0;
for (auto y : p)
if (y <= b) {
++cnt;
s += b-y;
}
} int count(long long c) {
if (c >= 2ll*(long long)N*(long long)K)
return 0;
int u = 0;
int v = N;
int ans = 0;
bool isGoRight = true;
long long f,f0;
int cnt,cnt0;
f = 0; cnt = 0;
while (u <= N && v >= 1) {
if (f == c)
++ans;
if (isGoRight) { // Go Right
++u;
getCount(p[u],v,cnt0,f0);
f += f0+(long long)cnt;
cnt += cnt0;
} else { // Go Down
getCount(rp[v],u,cnt0,f0);
--v;
cnt -= cnt0;
f -= f0+(long long)cnt;
}
isGoRight = f < c;
}
return ans;
} void work() {
cin>>N>>K;
for (int i = 0; i <= N; ++i) {
p[i].clear();
rp[i].clear();
}
int x,y;
for (int i = 0;i < K; ++i) {
cin>>x>>y;
p[x].push_back(y);
rp[y].push_back(x);
}
int Q;
cin>>Q;
long long c;
int ans;
for (int i = 0; i < Q; ++i) {
cin>>c;
ans = count(c);
if (i)
cout<<' '<<ans;
else
cout<<ans;
}
cout<<'\n';
} int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while (T--)
work();
return 0;
}

ZOJ 4082 Little Sub and his Geometry Problem题解的更多相关文章

  1. ZOJ - 4082:Little Sub and his Geometry Problem (双指针)

    Little Sub loves math very much, and has just come up with an interesting problem when he is working ...

  2. ZOJ Monthly, January 2019 Little Sub and his Geometry Problem 【推导 + 双指针】

    传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5861 Little Sub and his Geometry Prob ...

  3. HDU1086You can Solve a Geometry Problem too(判断线段相交)

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3 ...

  4. codeforces 361 E - Mike and Geometry Problem

    原题: Description Mike wants to prepare for IMO but he doesn't know geometry, so his teacher gave him ...

  5. hdu 1086 You can Solve a Geometry Problem too

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3 ...

  6. CodeForces 689E Mike and Geometry Problem (离散化+组合数)

    Mike and Geometry Problem 题目链接: http://acm.hust.edu.cn/vjudge/contest/121333#problem/I Description M ...

  7. Codeforces Gym 100338B Geometry Problem 计算几何

    Problem B. Geometry ProblemTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudg ...

  8. you can Solve a Geometry Problem too(hdoj1086)

    Problem Description Many geometry(几何)problems were designed in the ACM/ICPC. And now, I also prepare ...

  9. (hdu step 7.1.2)You can Solve a Geometry Problem too(乞讨n条线段,相交两者之间的段数)

    称号: You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/ ...

随机推荐

  1. Oracle中将列查询结果多行逗号拼接成一个大字段

    在11G以下版本中oracle有自带的函数wm_concat可以实现,如: select wm_concat(id) from table where col='1' 但是在12C版本中此函数无法使用 ...

  2. 不懂怎么创建可视化大屏?手把手教你使用数据可视化BI软件创建工厂车间数据监控大屏

    灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件.   本文以工厂车间数据监控大屏为例 ...

  3. 【转】Makefile步步为营

    Makefile步步为营 本目录主要包含Makefile一步步递进学习的示例代码 makefile代码实例:https://www.lanzous.com/i9m9npi step0:Makefile ...

  4. DOM基础+domReady+元素节点类型判断

    DOM节点类型  nodeType element  1    Node.ELEMENT_NODE   元素节点 attr  2   Node.ATTRIBUTE_NODE  属性节点 text  3 ...

  5. jQuery---each方法

    each方法 each方法 //each方法 $("li").each(function (index, element) { $(element).css("opaci ...

  6. 剑指offer-面试题39-数组中出现次数超过一半的数字-快速排序

    /* 题目: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输 ...

  7. js监听滚动结束

    使用setTimeout模拟滚动结束 let scrollTimer; document.addEventListener("scroll", () => { clearTi ...

  8. Swift Playgrounds for mac基础知识介绍

    Swift Playgrounds是一款适用于iPad和Mac的革命性应用程序,它使Swift学习变得互动而有趣.它不需要编码知识,因此非常适合刚开始的学生.使用Swift解决难题,以掌握基本知识.S ...

  9. 从应用的角度去学习Python--为孩子下载课本

    最近,孩子上课都没有课本,老师给发的是一个微信链接,打开看可以,打印打不全.怎么办?我就想既然能看,从爬虫的角度就一定可以抓下来! 在Chrome中打开网址,好家伙!一堆的Script之类的玩意儿.经 ...

  10. Kemaswill 机器学习 数据挖掘 推荐系统 Python optparser模块简介

      Python optparser模块简介