有一个 \(2^n\times 2^n\) 的网格,左下角坐标为 \((0,0)\),右上角坐标为 \((2^n,2^n)\)。spa
定义格点 \((x,y)\) 为坐标系中坐标为 \((x,y)\) 的整点。code
定义格子 \((x,y)\) 为左下角格点为 \((x,y)\),右上角格点为 \((x+1,y+1)\) 的格子。blog
你要给每一个格子标号:若一个格子的坐标为 \((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\) 个点的简单多边形。这个多边形的全部顶点都是整点,全部边都与坐标轴平行。get
记 \(C\) 为多边形内全部格子的编号组成的集合。string
你每次操做能够选择两个数 \([l,r]\),删去 \(C\) 中 \([l,r]\) 之间的全部数,代价为 \(r-l+1\)。it
每次给你一个 \(k\),问你在操做不超过 \(k\) 次的状况下删去 \(C\) 中的全部数,最少总代价是多少。io
\(n\leq 30,m\leq 200,q\leq {10}^6\)class
先把 \(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; }