题解 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;
}
posted @ 2021-07-28 19:02  Administrator-09  阅读(18)  评论(0编辑  收藏  举报