1. 程式人生 > 其它 >題解 queen(留坑)

題解 queen(留坑)

傳送門

部落格園突然打不開了,奇奇怪怪的……
少寫個等號沒看出來 nm寫反了沒看出來 考完5min全拍出來了
手殘屬性加持 不對拍等於爆零
yysy,我連盧卡斯定理的存在都忘了……

發現要讓一大堆皇后能互相攻擊,它們貌似只能在同一條直線上
然後發現皇后數量較少的時候好像有特例
所以特判即可
\(O(n)\)解法需要列舉邊長,考慮如何優化
列舉邊長是省不掉的,考慮處理下柿子

\[\sum\limits_{i=1}^{min(n,m)-1}(n-i)(m-i) = \sum\limits_{i=1}^{min(n,m)-1}nm-(n+m)+i^2 = (min(n,m)-1)nm-(n+m)\sum\limits_{i=1}^{min(n,m)-1}i+\sum\limits_{i=1}^{min(n,m)-1}i^2 \]
  • 有個式子:\(\sum\limits_{i=1}^n i^2 = \frac{n(n+1)(2n+1)}{6}\)

    同理,[留坑]

然後還有一個需要處理的式子是 \(\sum\limits_{i=k}^n C_i^k\)

\[\sum\limits_{i=k}^n C_i^k = C_{k+1}^{k+1}+\sum\limits_{i=k+1}^n C_i^k = C_{k+1}^{k+1}+C_{k+1}^k+\sum\limits_{i=k+2}^n C_i^k \]

發現這兩項可以組合,即為

\[C_{k+1}^k + \sum\limits_{i=k+2}^n C_i^k \]

依次組合,最終原式等於 \(C_{n+1}^{k+1}\)

  • 結論:\(\sum\limits_{i=0}^n C_i^k = C_{n+1}^{k+1}\)

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 310010
#define ll long long 
#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

ll n, m, k, kn, km;
ll fac[N], inv1[N], inv2[N];
const ll p=3e5+7;
inline ll C(ll n, ll k) {return n>=k?fac[n]*inv2[k]%p*inv2[n-k]%p:0;}
inline ll lucas(ll n, ll k) {return !k?1:lucas(n/p, k/p)*C(n%p, k%p)%p;}

namespace task1{
	inline ll sig(ll n) {n%=p; return n*(n+1)*inv1[2]%p;}
	inline ll sig2(ll n) {n%=p; return n*(n+1)%p*(n*2+1)%p*inv1[6]%p;}
	void solve() {
		ll ans=0, lim;
		n=read(); m=read(); k=read();
		kn=n%p; km=m%p;
		if (k==1) {printf("%lld\n", (kn*km)%p); return ;}
		if (k==3) {
			lim=(min(n, m)-1)%p; ans+=4ll*(lim*kn%p*km%p - (kn+km)%p*sig(lim)%p + sig2(lim))%p, ans%=p;
			lim=min((n-1)/2, m-1)%p; ans+=2ll*(lim*kn%p*km%p - (2ll*km+kn)%p*sig(lim)%p + 2ll*sig2(lim))%p, ans%=p;
			lim=min(n-1, (m-1)/2)%p; ans+=2ll*(lim*kn%p*km%p - (2ll*kn+km)%p*sig(lim)%p + 2ll*sig2(lim))%p, ans%=p;
		}
		if (k==4) {
			lim=min((n-1)/2, m-1)%p; ans+=2ll*(lim*kn%p*km%p - (2ll*km+kn)%p*sig(lim)%p + 2ll*sig2(lim))%p, ans%=p;
			lim=min(n-1, (m-1)/2)%p; ans+=2ll*(lim*kn%p*km%p - (2ll*kn+km)%p*sig(lim)%p + 2ll*sig2(lim))%p, ans%=p;
			lim=(min(n, m)-1)%p; ans+=(lim*kn%p*km%p - (kn+km)%p*sig(lim)%p + sig2(lim))%p, ans%=p;
			lim=((min(n, m)-1)/2)%p; ans+=5ll*(lim*kn%p*km%p - 2ll*(kn+km)%p*sig(lim)%p + 4ll*sig2(lim))%p, ans%=p;
		}
		if (k==5) {lim=((min(n, m)-1)/2)%p; ans+=2ll*(lim*kn%p*km%p - 2ll*(kn+km)%p*sig(lim)%p + 4ll*sig2(lim))%p, ans%=p;}
		if (m>=k) ans+=kn*lucas(m, k)%p, ans%=p;
		if (n>=k) ans+=km*lucas(n, k)%p, ans%=p;
		if (n>=k && m>=k) {
			ans+=4ll*lucas(min(n, m), k+1)%p, ans%=p;
			ans+=2ll*(max(n, m)-min(n, m)+1)%p*lucas(min(n, m), k)%p, ans%=p;
		}
		printf("%lld\n", (ans%p+p)%p);
	}
}

signed main()
{
	int T;
	
	T=read();
	fac[0]=fac[1]=1; inv1[0]=inv1[1]=1; inv2[0]=inv2[1]=1;
	for (int i=2; i<N; ++i) fac[i]=fac[i-1]*i%p;
	for (int i=2; i<N; ++i) inv1[i]=(p-p/i)*inv1[p%i]%p;
	for (int i=2; i<N; ++i) inv2[i]=inv1[i]*inv2[i-1]%p;
	while (T--) task1::solve();
	
	return 0;
}