表格(拉格朗日插值法)

衆所周知,Logx精通Excel。
他覺得表格只有單調的白色非常無聊,他決定將一些單元格塗黑。

在一個n行m列的表格裏,剛開始所有單元格都是白的。
Logx打算在這個表格選出三個不同的單元格A(x1,y1),B(x2,y2),C(x3,y3),並將選中的三個單元格塗黑。
爲了使表格看起來美觀,Logx會使每一行和每一列均至多有一個格子被塗黑。
他稱一種選擇方案是好的,當且僅當L≤|x1-x2|+|y1-y2|+|x2-x3|+|y2-y3|+|x1-x3|+|y1-y3|≤R,即這三個黑格子之間兩兩的曼哈頓距離之和在區間[L,R]內。其中L,R是他給定的兩個常數。
兩種方案不同,當且僅當存在一個格子,在一種方案中被塗黑了,在另一種方案中沒有被塗黑。
Logx想要知道,有多少種選擇方案是好的。
 

輸入

輸入僅一行,包含四個正整數 n,m,L,R,含義見題目描述。

輸出

輸出一行一個整數表示方案數。
由於答案可能很大,你只要輸出方案數對10^9+7取模的結果。

 

樣例輸入 Copy

【樣例1】
3 3 1 20000
【樣例2】
3 3 4 7
【樣例3】
4 6 9 12
【樣例4】
7 5 13 18
【樣例5】
4000 4000 4000 14000

樣例輸出 Copy

【樣例1】
6
【樣例2】
0
【樣例3】
264
【樣例4】
1212
【樣例5】
859690013

提示

對於所有數據,3≤n,m≤10^16,1≤L≤R≤10^18。

 

結論:

1. 設三個不在同行同列的黑格子所圍成的長方形爲x * y,那麼三個黑格子兩兩之間距離和爲2 * (x + y - 2);

2. 設三個不在同行同列的黑格子所圍成的長方形爲x * y,有6 * (x - 2) * (y - 2)種方法放置三個黑格子;

3. 一個大小爲x * y的長方形在n * m的格子中有(n - x + 1) * (m - y + 1);

 

首先將(L, R)區間拆成(1,R) - (1, L - 1)

所以

 

 

H1(x)用拉格朗日插值法算出來

H2(x)可以直接用公式或者同第一步用拉格朗日插值

最暴力的代碼O(n*m)

/**/
#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const long long mod = 1e9 + 7;

LL n, m, l, r;
LL pw6, pw2;

LL poww(LL x, LL num){
	LL res = 1;
	while(num){
		if(num & 1) res = res * x % mod;
		x = x * x % mod;
		num >>= 1;
	}
	return res;
}

LL cal(LL x, LL y){
	return (x - 2) * (y - 2) % mod * 6 % mod;
}

LL cal1(LL x){
	return x * (x + 1) % mod * (2 * x + 1) % mod * pw6 % mod;
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	pw6 = poww(6, mod - 2);
	pw2 = poww(2, mod - 2);
	scanf("%lld %lld %lld %lld", &n, &m, &l, &r);
	LL ans = 0;
	for (LL i = 3; i <= min(r / 2 - 1, n); i++){
		LL L = max(3LL, (l + 1) / 2 + 2 - i), R = min(2 - i + r / 2, m);
		for (LL j = L; j <= R; j++){
			ans += cal(i % mod, j % mod) * ((n - i + 1) % mod) % mod * ((m - j + 1) % mod) % mod;
			ans %= mod;
		}
	}
	printf("%lld\n", ans);

	return 0;
}
/**/

暴力代碼(n)

/**/
#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const long long mod = 1e9 + 7;

LL n, m, l, r;
LL pw6, pw2;

LL poww(LL x, LL num){
	LL res = 1;
	while(num){
		if(num & 1) res = res * x % mod;
		x = x * x % mod;
		num >>= 1;
	}
	return res;
}

LL cal(LL x, LL y){
	return (x - 2) * (y - 2) % mod * 6 % mod;
}

LL cal1(LL x){
	return x * (x + 1) % mod * (2 * x + 1) % mod * pw6 % mod;
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	pw6 = poww(6, mod - 2);
	pw2 = poww(2, mod - 2);
	scanf("%lld %lld %lld %lld", &n, &m, &l, &r);
	LL ans = 0;
	for (LL i = 3; i <= min(r / 2 - 1, n); i++){
		LL L = max(3LL, (l + 1) / 2 + 2 - i), R = min(2 - i + r / 2, m);
		LL t1 = (cal1((L - 1) % mod) - cal1(R % mod)) % mod;
		LL t2 = (m + 3) % mod * ((R - L + 1) % mod) % mod * ((R + L) % mod) % mod * pw2 % mod;
		LL t3 = 2 * (m + 1) % mod * ((R - L + 1) % mod) % mod;
		LL t = ((t1 + t2 - t3) % mod + mod) % mod;
		ans = (ans + t * 6 % mod * ((i - 2) % mod) % mod * ((n - i + 1) % mod) % mod) % mod;
	}
	printf("%lld\n", ans);

	return 0;
}
/**/

AC代碼:

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const int D = 1e3 + 10;

const long long mod = 1e9 + 7;

LL n, m, l, r, R, pw2, pw6;
LL a[D], f[D], g[D], p[D], p1[D], p2[D], b[D], h[D][2], C[D];

LL poww(LL x, LL num){
	LL res = 1;
	while(num){
		if(num & 1) res = res * x % mod;
		x = x * x % mod;
		num >>= 1;
	}
	return res;
}

void init(int M){
	f[0] = f[1] = g[0] = g[1] = 1;
	for (int i = 2; i <= M + 4; i++) f[i] = f[i - 1] * i % mod;
	g[M + 4] = poww(f[M + 4], mod - 2);
	for (int i = M + 3; i >= 1; i--) g[i] = g[i + 1] * (i + 1) % mod;
}

LL sum(LL x, LL y){
	return ((x - 2) % mod) * ((y - x + 1) % mod) % mod;
}

LL calcn(int d, LL *a, LL n){// a[0].. a[d]  a[n]
	if(n <= d) return a[n];
	p1[0] = p2[0] = 1;
	for (int i = 0; i <= d; i++){
		LL t = (n - i + mod) % mod;
		p1[i + 1] = p1[i] * t % mod;
	}
	for (int i = 0; i <= d; i++){
		LL t = (n - d + i + mod) % mod;
		p2[i + 1] = p2[i] * t % mod;
	}
	LL ans = 0;
	for (int i = 0; i <= d; i++){
		LL t = g[i] * g[d - i] % mod * p1[i] % mod * p2[d - i] % mod * a[i] % mod;
		if((d - i) & 1) ans = (ans - t + mod) % mod;
		else ans = (ans + t) % mod;
	}
	return ans;
}

LL polysum(LL m, LL *a, LL n){// a[0].. a[m] \sum_{i=0}^{n} a[i]
	if(n <= m){
		LL sum = 0;
		for (int i = 0; i <= n; i++) sum = (sum + a[i]) % mod;
		return sum;
	}
	LL b[D];
	for (int i = 0; i <= m; i++) b[i] = a[i];
	b[m + 1] = calcn(m, b, m + 1);
	for (int i = 1; i <= m + 1; i++) b[i] = (b[i - 1] + b[i]) % mod;
	return calcn(m + 1, b, n);// m次多項式的和是m+1 次多項式
}

LL cal3(LL x){
	return x * (x + 1) % mod * (2 * x + 1) % mod * pw6 % mod;
}

LL solve(LL L, LL R){
	if(L > R) return 0LL;
	LL t1 = (cal3((L - 1) % mod) - cal3(R % mod)) % mod;
	LL t2 = (m + 3) % mod * ((R - L + 1) % mod) % mod * ((R + L) % mod) % mod * pw2 % mod;
	LL t3 = 2 * (m + 1) % mod * ((R - L + 1) % mod) % mod;
	LL t = ((t1 + t2 - t3) % mod + mod) % mod;
	return t;
}

LL cal1(LL l, LL r){
	if(l > r) return 0LL;
	LL a[15];
	for (int i = 0; i <= 5; i++) a[i] = sum(l + i, n) * solve(3, R / 2 - l - i + 2) % mod;
	return polysum(5, a, r - l);
}

LL cal2(LL l, LL r){
	if(l > r) return 0LL;
	LL a[15];
	a[0] = 0;
	for (int i = 0; i <= 2; i++) a[i] = sum(l + i, n) * solve(3, m) % mod;
	return polysum(2, a, r - l);
}

LL cal(LL x){
	if(!x) return 0LL;
	LL L1 = x / 2 - m + 2, R1 = min(n, x / 2 - 1);
	LL L2 = 3, R2 = x / 2 - m + 1;
	if(R2 < L2) return cal1(max(3LL, L1), R1);
	else if(R2 >= n) return cal2(L2, min(R2, n));
	else return cal1(L1, R1) + cal2(L2, R2);
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	pw2 = poww(2, mod - 2), pw6 = poww(6, mod - 2);
	init(1000);
	scanf("%lld %lld %lld %lld", &n, &m, &l, &r);
	R = r;
	LL ans = cal(r);
	R = l - 1;
	ans -= cal(l - 1);
	printf("%lld\n", (ans + mod) % mod * 6 % mod);

	return 0;
}
/**/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章