【數學】[Baltic2016][BZOJ5184] Spiral

分析:

噁心至極。。。
首先,把圖拆成一個個的環,
第一層是:1
第二層是:2,3,4,5,6,7,8,9
……
然後,就可以發現,單獨的一個環的貢獻,可以在O(1)複雜度內算出來。(拆成四條邊)

然而這要T

問題就在於如何快速求多個環的貢獻。

首先,我們可以把原矩陣也拆分了,拆分成數個部分環的組合:
在這裏插入圖片描述
這樣一來,每個部分環中,被剖分的矩形只有兩種可能:
在這裏插入圖片描述
在這裏插入圖片描述
可以通過推倒證明,在這兩種情況下,每一個環的貢獻一定滿足:
Si=Ai3+Bi2+Ci1+Di0Si=A*i^3+B*i^2+C*i^1+D*i^0
(其中i表示是從上一層開始的第i個環)

所以,要求K個環的貢獻和,就只需要算:
A(03+13+23++k1)3)+B(02+12++(j1)2)+C(01+11++k1)1)+D(00+10+20++(k1)0)A*(0^3+1^3+2^3+……+(k-1)^3)+B*(0^2+1^2+……+(j-1)^2)+C*(0^1+1^1+……+(k-1)^1)+D*(0^0+1^0+2^0+……+(k-1)^0)
這幾個都是有公式的,自己去套就好了。

然後,從證明過程中可以看出,推出A,B,C,D是幾乎不可能的。但有一個更好的方法:我們可以暴力算出前4個環的貢獻,然後將A,B,C,D反解出來。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
#define MOD 1000000007
#define y0 warspitewarspitewarspitewarspitewarspitewarspite
using namespace std;
typedef long long ll;
vector<ll> st;
ll ans;
ll inv6=(MOD+1ll)/6ll,inv2=(MOD+1ll)/2ll,v[5];
ll pres(ll x){
	return (1ll+x)*x/2ll%MOD;
}
ll calc(ll l1,ll r1,ll l2,ll r2,ll val){
	ll l=max(l1,l2);
	ll r=min(r1,r2);
	if(l<=r)
		return (pres(r)-pres(l-1)+(r-l+1)*(val%MOD)%MOD)%MOD;
	return 0;
}
ll count(ll L,ll l,ll r,ll d,ll u){
	if(L==0)
		return 	l<=0&&r>=0&&u>=0&&d<=0;
	ll val=(2ll*L+1ll)*(2ll*L+1ll);
	ll res=0;
	val-=L;
	if(u>=-L&&d<=-L)
		res=res+calc(l,r,-L,L,val);
	val-=2ll*L;
	if(l<=-L&&r>=-L)
		res=res+calc(d,u,-L+1,L-1,val);
	val-=2ll*L;
	if(u>=L&&d<=L)
		res=res+calc(l,r,-L,L,val);
	val-=2ll*L;
	if(l<=L&&r>=L)
		res=res+calc(d,u,-L+1,L-1,val);
	res=(res%MOD+MOD)%MOD;
	return res;
}	
int main(){
//	freopen("t.in.4","r",stdin);
//	freopen("wa.out","w",stdout);
	int n,q;
	SF("%d%d",&n,&q);
	for(int i=1;i<=q;i++){
		ans=0;
		ll x0,x1,y0,y1;
		SF("%lld%lld%lld%lld",&x0,&y0,&x1,&y1);
		st.clear();
		st.push_back(0);
		st.push_back(1);
		st.push_back(2);
		st.push_back(abs(x0)-1);
		st.push_back(abs(x0));
		st.push_back(abs(x0)+1);
		st.push_back(abs(x1)-1);
		st.push_back(abs(x1));
		st.push_back(abs(x1)+1);
		st.push_back(abs(y0)-1);
		st.push_back(abs(y0));
		st.push_back(abs(y0)+1);
		st.push_back(abs(y1)-1);
		st.push_back(abs(y1));
		st.push_back(abs(y1)+1);
		sort(st.begin(),st.end());
		for(int i=1;i<int(st.size());i++){
			int las=st[i-1];
			int now=st[i];
			if(las<0||las==now)
				continue;
			int k=now-las;
			if(k<4){
				for(int i=las;i<now;i++)
					(ans+=count(i,x0,x1,y0,y1))%=MOD;
			}
			else{
				for(int i=0;i<4;i++)
					v[i]=count(i+las,x0,x1,y0,y1);
				ll A=(((v[3]-2ll*v[2]+v[1])-(v[2]-2ll*v[1]+v[0]))%MOD+MOD)%MOD;
				A=A*inv6%MOD;
				v[1]=(v[1]-A+MOD)%MOD;
				v[2]=(v[2]-8ll*A%MOD+MOD)%MOD;
				v[3]=(v[3]-27ll*A%MOD+MOD)%MOD;
				ll B=((v[2]-2ll*v[1]+v[0])%MOD+MOD)%MOD;
				B=B*inv2%MOD;
				v[1]=(v[1]-B+MOD)%MOD;
				v[2]=(v[2]-4ll*B%MOD+MOD)%MOD;
				v[3]=(v[3]-9ll*B%MOD+MOD)%MOD;
				ll C=v[1]-v[0];
				ll D=v[0];
				ll K=k;
				ll SUM=K*(K-1ll)%MOD*inv2%MOD;
//				PF("{%lld %lld %lld %lld(%lld,%lld,%lld,%lld) [%d %d]}\n",A,B,C,D,v[0],v[1],v[2],v[3],las,now);
				ans=(ans+K*D%MOD)%MOD;
				ans=(ans+SUM*C%MOD)%MOD;
				ans=(ans+K*(K-1ll)%MOD*(2ll*k-1ll)%MOD*inv6%MOD*B%MOD)%MOD;
				ans=(ans+SUM*SUM%MOD*A%MOD)%MOD;
			}
		}
		ans=(ans+MOD)%MOD;
		PF("%lld\n",ans);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章