题解:P4676 [BalticOI 2016] Spiral (day1)
lailai0916 · · 题解
题意简述
在边长为
解题思路
先推导一个象限内的二维前缀和,再把询问矩形拆到四个方向中。
从正
其中:
把第
记该位置的编号为
先计算轴上的前缀和:
约定
再记
把各层求和并化简,得到:
其中:
接着计算任意局部前缀矩形。记
当
有了
如果让四个象限都包含坐标轴,最后还要逐段减去重复轴。可以直接把整张平面划分为四个互不相交的区域,并把原点单独处理:
| 全局坐标范围 | 局部坐标 |
|
|---|---|---|
四个区域恰好覆盖原点以外的所有格点,而且没有交集。对每次询问,分别求原矩形与这四个区域的交集,将交集端点转换为局部非负坐标,再调用局部矩形和。若询问包含原点,最后额外加上
公式中的除法在模意义下分别乘以
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll mod=1000000007;
const ll inv2=500000004;
const ll inv3=333333336;
const int cg[4]={-1,1,3,-3};
const int cf[4]={2,4,2,0};
const int cp[4]={1,2,3,0};
ll fix(ll x)
{
x%=mod;
if(x<0)x+=mod;
return x;
}
ll add(ll x,ll y)
{
return fix(x+y);
}
ll sub(ll x,ll y)
{
return fix(x-y);
}
ll mul(ll x,ll y)
{
return fix(x)*fix(y)%mod;
}
ll g(int op,ll x)
{
if(x<0)return 0;
ll a=fix(x);
ll b=add(a,1);
ll ans=mul(mul(mul(2,a),b),add(mul(2,a),1));
ans=mul(ans,inv3);
ans=add(ans,mul(cg[op],mul(mul(a,b),inv2)));
return add(ans,b);
}
ll f(int op,ll x)
{
ll a=fix(x);
ll b=add(a,1);
ll ans=add(mul(2,mul(mul(a,a),mul(b,b))),b);
ll sum=mul(mul(mul(a,b),add(mul(2,a),1)),inv3);
ans=add(ans,mul(cf[op],sum));
return add(ans,mul(cp[op],mul(a,b)));
}
ll prefix(int op,ll x,ll y)
{
if(x<0||y<0)return 0;
if(x==y)return f(op,x);
if(x>y)
{
ll sum=mul(2,sub(g(op,x),g(op,y)));
sum=add(sum,mul(x-y,y));
return add(f(op,y),mul(mul(sum,y+1),inv2));
}
ll sum=mul(2,sub(g((op+1)%4,y),g((op+1)%4,x)));
sum=sub(sum,mul(y-x,x));
return add(f(op,x),mul(mul(sum,x+1),inv2));
}
ll query(int op,ll x1,ll y1,ll x2,ll y2)
{
ll ans=sub(prefix(op,x2,y2),prefix(op,x1-1,y2));
ans=sub(ans,prefix(op,x2,y1-1));
return add(ans,prefix(op,x1-1,y1-1));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n;
int q;
cin>>n>>q;
while(q--)
{
ll x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
ll ans=0;
if(x1<=0&&y2>=1)
{
ll rx=min(x2,0LL);
ll ly=max(y1,1LL);
ans=add(ans,query(0,ly,-rx,y2,-x1));
}
if(x1<=-1&&y1<=0)
{
ll rx=min(x2,-1LL);
ll ry=min(y2,0LL);
ans=add(ans,query(1,-rx,-ry,-x1,-y1));
}
if(x2>=0&&y1<=-1)
{
ll lx=max(x1,0LL);
ll ry=min(y2,-1LL);
ans=add(ans,query(2,-ry,lx,-y1,x2));
}
if(x2>=1&&y2>=0)
{
ll lx=max(x1,1LL);
ll ly=max(y1,0LL);
ans=add(ans,query(3,lx,ly,x2,y2));
}
if(x1<=0&&x2>=0&&y1<=0&&y2>=0)ans=add(ans,1);
cout<<ans<<'\n';
}
return 0;
}