【CERC2016】【BZOJ4792】村庄 搜索
题目大意
有一个 \(2^n\times 2^n\) 的网格,左下角坐标为 \((0,0)\),右上角坐标为 \((2^n,2^n)\)。
定义格点 \((x,y)\) 为坐标系中坐标为 \((x,y)\) 的整点。
定义格子 \((x,y)\) 为左下角格点为 \((x,y)\),右上角格点为 \((x+1,y+1)\) 的格子。
你要给每个格子标号:若一个格子的坐标为 \((x,y)\),其中 \(x=(x_0x_1\ldots x_{n-1}),y=(y_0y_1\ldots y_{n-1})\),则这个格子的编号为 \((x_0y_0x_1y_1\ldots x_{n-1}y_{n-1})\)。
网格上有一个 \(m\) 个点的简单多边形。这个多边形的所有顶点都是整点,所有边都与坐标轴平行。
记 \(C\) 为多边形内所有格子的编号组成的集合。
你每次操作可以选择两个数 \([l,r]\),删去 \(C\) 中 \([l,r]\) 之间的所有数,代价为 \(r-l+1\)。
每次给你一个 \(k\),问你在操作不超过 \(k\) 次的情况下删去 \(C\) 中的所有数,最少总代价是多少。
\(n\leq 30,m\leq 200,q\leq {10}^6\)
题解
先把 \(C\) 中所有连续段找出来。记个数为 \(cnt\),\(\lvert C\rvert =tot\)。
那么当 \(k\geq cnt\) 时答案为 \(tot\)。
当 \(k\) 变小时,每次要选两个相邻的连续段,把这两个连续段中间的空隙填上。
显然每次选的一定是最小的空隙。
那么我们只用处理出每种长度的空隙的个数就好了。
先讲一下官方题解的做法:
对于一个矩形,我们求出这个矩形内所有空隙的长度和多边形与这个矩形的交中编号最小最大的点。
每次对于一个矩形 \((xl,xr,yl,yr)\),如果这个矩形是正方形,就把这个矩形沿着 \(x=\frac{(xl+xr)}{2}\) 切开,否则就沿着 \(y=\frac{yl+yr}{2}\) 切开。当然你把每个正方形都切成四块也是可以的。
这样每个矩形内的格子的编号都是连续的。
如果切开来的两个矩形形状相同,就只递归一边,否则就两边都递归。
每次会产生多个长度为 \(s2.min-s1.max-1\) 的空隙。
题解说这样做的时间复杂度是 \(O(nm^3)\) 的。
有一个更好的做法:
首先,矩形和空隙长度都只有 \(O(nm)\) 种。
搜索树有 \(O(n)\) 层。对于搜索的树每一层,把多边形放到这一层所有矩形组成的网格中。
把多边形顶点所在的矩形染成红色,把与红色矩形相邻的矩形染成蓝色,剩下的矩形是白色的。
对于一个白色的矩形,如果这个矩形没有被多边形完全覆盖,也没有和多边形相离,那么这个矩形一定和某一个蓝色矩形是相同的。
这样每层只有 \(O(m)\) 个矩形,总共有 \(O(nm)\) 个矩形。所以空隙长度也只有 \(O(nm)\) 种。
直接把每个矩形哈希下来跑 BFS 即可。
时间复杂度:\(O(nm^2)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=10000;
const int M=100000;
const ll p=1000000007;
const ll w1=127;
const ll w2=129;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
const ll inv1=fp(w1-1,p-2);
const ll inv2=fp(w2-1,p-2);
int min(int a,int b)
{
return a<b?a:b;
}
int max(int a,int b)
{
return a>b?a:b;
}
ll pw1[2][50000],pw2[2][50000];
struct point{int x,y;};
int n,m;
point a[M];
void init()
{
ll v=w1;
for(int i=0;i<=1;i++)
{
pw1[i][0]=1;
for(int j=1;j<=1<<15;j++)
pw1[i][j]=pw1[i][j-1]*v%p;
v=pw1[i][1<<15];
}
v=w2;
for(int i=0;i<=1;i++)
{
pw2[i][0]=1;
for(int j=1;j<=1<<15;j++)
pw2[i][j]=pw2[i][j-1]*v%p;
v=pw2[i][1<<15];
}
}
ll pow1(ll x)
{
return pw1[1][x>>15]*pw1[0][x&((1<<15)-1)]%p;
}
ll pow_sum1(ll x)
{
return (pow1(x+1)-1)*inv1%p;
}
ll calc1(ll l,ll r)
{
return pow_sum1(r-l)*pow1(l)%p;
}
ll pow2(ll x)
{
return pw2[1][x>>15]*pw2[0][x&((1<<15)-1)]%p;
}
ll pow_sum2(ll x)
{
return (pow2(x+1)-1)*inv2%p;
}
ll calc2(ll l,ll r)
{
return pow_sum2(r-l)*pow2(l)%p;
}
struct rect
{
int xl,xr,yl,yr;
rect(int a=0,int b=0,int c=0,int d=0):xl(a),xr(b),yl(c),yr(d){}
};
map<ll,ll> g;
map<ll,int> c[32];
rect d[100000];
ll f[100000];
ll h[100000];
pll s[100000];
int c22[100000];
int c21[100000];
int c11[100000];
int c12[100000];
int num;
int __;
ll insert(int xl,int xr,int yl,int yr,int x,ll v)
{
ll s=0;
for(int i=1;i<=m;i++)
{
__++;
int _=(i==m?1:i+1);
if(a[i].y!=a[_].y||a[i].y>yr)
continue;
int x1=min(a[i].x,a[_].x);
int x2=max(a[i].x,a[_].x);
if(x1>xr||x2<xl)
continue;
int y1=max(a[i].y,yl);
int y2=yr;
x1<xl?x1=xl:0;
x2>xr?x2=xr:0;
if(a[i].x<a[_].x)
s+=calc1(x1-xl,x2-xl-1)*calc2(y1-yl,y2-yl-1)%p;
else
s-=calc1(x1-xl,x2-xl-1)*calc2(y1-yl,y2-yl-1)%p;
}
s=(s%p+p)%p;
int &o=c[x][s];
if(!o)
{
num++;
o=num;
h[num]=s;
d[num]=rect(xl,xr,yl,yr);
}
f[o]+=v;
return o;
}
pll e[1000000];
ll s1[1000000],s2[1000000];
int t;
int main()
{
#ifndef ONLINE_JUDGE
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
#endif
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&a[i].x,&a[i].y);
int rt=insert(0,1<<n,0,1<<n,n,1);
for(int i=n;i>=1;i--)
{
for(auto v:c[i])
{
int xl=d[v.second].xl;
int xr=d[v.second].xr;
int yl=d[v.second].yl;
int yr=d[v.second].yr;
ll _=f[v.second];
int xmid=(xl+xr)>>1;
int ymid=(yl+yr)>>1;
c11[v.second]=insert(xl,xmid,yl,ymid,i-1,_);
c12[v.second]=insert(xl,xmid,ymid,yr,i-1,_);
c21[v.second]=insert(xmid,xr,yl,ymid,i-1,_);
c22[v.second]=insert(xmid,xr,ymid,yr,i-1,_);
}
}
fprintf(stderr,"%d\n",__);
// return 0;
for(int i=num;i>=1;i--)
{
int xl=d[i].xl;
int xr=d[i].xr;
int yl=d[i].yl;
int yr=d[i].yr;
ll area=ll(xr-xl)*(yr-yl);
if(area==1)
{
if(h[i]==1)
s[i]=pll(0,0);
else
s[i]=pll(-1,-1);
continue;
}
pll s1,s2;
pll s11=s[c11[i]],s12=s[c12[i]];
if(s12.first==-1)
s1=s11;
else if(s11.first==-1)
s1=pll(s12.first+area/4,s12.second+area/4);
else
{
s12.first+=area/4;
s12.second+=area/4;
g[s12.first-s11.second-1]+=f[i];
s1=pll(s11.first,s12.second);
}
pll s21=s[c21[i]],s22=s[c22[i]];
if(s22.first==-1)
s2=s21;
else if(s21.first==-1)
s2=pll(s22.first+area/4,s22.second+area/4);
else
{
s22.first+=area/4;
s22.second+=area/4;
g[s22.first-s21.second-1]+=f[i];
s2=pll(s21.first,s22.second);
}
if(s2.first==-1)
s[i]=s1;
else if(s1.first==-1)
s[i]=pll(s2.first+area/2,s2.second+area/2);
else
{
s2.first+=area/2;
s2.second+=area/2;
g[s2.first-s1.second-1]+=f[i];
s[i]=pll(s1.first,s2.second);
}
}
pll all=s[rt];
g.erase(0);
ll cnt=1,tot=all.second-all.first+1;
for(auto v:g)
{
e[++t]=v;
tot-=v.first*v.second;
cnt+=v.second;
}
sort(e+1,e+t+1);
for(int i=1;i<=t;i++)
{
s1[i]=s1[i-1]+e[i].second;
s2[i]=s2[i-1]+e[i].first*e[i].second;
}
// return 0;
int q;
ll x;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
x=rd();
if(x>=cnt)
printf("%lld\n",tot);
else
{
x=cnt-x;
ll ans=tot;
int y=upper_bound(s1+1,s1+t+1,x)-s1;
ans+=s2[y-1];
ans+=e[y].first*(x-s1[y-1]);
printf("%lld\n",ans);
}
}
return 0;
}
【CERC2016】【BZOJ4792】村庄 搜索的更多相关文章
- P1171 售货员的难题--搜索(剪枝)
题目背景 数据有更改 题目描述 某乡有nn个村庄(1<n \le 201<n≤20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)s(0<s ...
- SQLSERVER走起微信公众帐号已经开通搜狗微信搜索
SQLSERVER走起微信公众帐号已经开通搜狗微信搜索 请打开下面链接 http://weixin.sogou.com/gzh?openid=oIWsFt-hiIb_oYqQHaBMoNwRB2wM ...
- solr_架构案例【京东站内搜索】(附程序源代码)
注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的. 一:solr服务的端口号.我这里的sol ...
- SQLServer地址搜索性能优化例子
这是一个很久以前的例子,现在在整理资料时无意发现,就拿出来再改写分享. 1.需求 1.1 基本需求: 根据输入的地址关键字,搜索出完整的地址路径,耗时要控制在几十毫秒内. 1.2 数据库地址表结构和数 ...
- HTML5轻松实现搜索框提示文字点击消失---及placeholder颜色的设置
在做搜索框的时候无意间发现html5的input里有个placeholder属性能轻松实现提示文字点击消失功能,之前还傻傻的在用js来实现类似功能... 示例 <form action=&quo ...
- bzoj1079--记忆化搜索
题目大意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得 ...
- bzoj3208--记忆化搜索
题目大意: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目. 我们可以把风景区看作一个n*n的地图,每个点有它的初始高度,滑雪只能从高处往低处滑[严格大于] ...
- Android中通过ActionBar为标题栏添加搜索以及分享视窗
在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果.Action ...
- 一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
随机推荐
- Unable to execute 'doFinal' with cipher instance [javax.crypto.Cipher@4e025e0a]
org.apache.shiro.crypto.CryptoException: Unable to execute 'doFinal' with cipher instance [javax.cry ...
- nginx系列10:通过upstream模块选择上游服务器和负载均衡策略round-robin
upstream模块的使用方法 1,使用upstream和server指令来选择上游服务器 这两个指令的语法如下图: 示例: 2,对上游服务使用keepalive长连接 负载均衡策略round-rob ...
- setTimeout传参 和 运行机制
1.setTimeout 传参数 setTimeout还允许添加更多的参数.它们将被传入推迟执行的函数(回调函数) 上面代码中,setTimeout共有4个参数.最后那两个参数,将在1000毫秒之后回 ...
- ArcPy 拷贝数据库
使用Python脚本进行图形数据库的拷贝. 原始帖子地址:https://www.2cto.com/database/201302/187391.html 整理Python代码: # -*- codi ...
- 数据结构java(一)数组链表
链表是数据结构中最基础的内容,链表在存储结构上分成两种:数组形式储存,链式存储. 相比c语言需要的结构体,在java中由于有了面向对象编程,将指针‘藏’了起来,不需要分配内存. 所以只需要创建一个对象 ...
- DVWA 黑客攻防演练(十一) 存储型 XSS 攻击 Stored Cross Site Scripting
上一篇文章会介绍了反射型 XSS 攻击.本文主要是通过 dvwa 介绍存储型 XSS 攻击.存储型 XSS 攻击影响范围极大.比如是微博.贴吧之类的,若有注入漏洞,再假如攻击者能用上一篇文章类似的代码 ...
- <%@ Register TagPrefix="uc1" TagName="user" Src="../Control/user.ascx" %>什么意思?
TagPrefix定义控件位置的命名空间.有了命名空间制约,就可以在同一个网页里使用不同功能的同名控件. TagName指向所使用控件的名字.在同一个命名空间里的控件名是唯一的.控件名一般都表明控件的 ...
- 迁移FRS至DFSR SYSVOL
截至2017年6月20日,Windows 2016 RS1系统为最后一版支持FRS,后续版本将不再包含该功能,详细见 https://support.microsoft.com/en-us/help/ ...
- 金蝶K3外购入库单单价取数规则调整
涉及界面: 问题:财务抱怨外购入库单价格取错,单价多除了一次税率 例如,采购单里面注明了价格是不含税15.3256 结果在外购入库单里面,又自做主张除以税率17%,把采购成本搞成了13.0988, 咨 ...
- [ gczdac ] HDU1000
地址:http://acm.hdu.edu.cn/showproblem.php?pid=1000 Problem Description Calculate A + B. Input Eac ...