題解 queen(留坑)
阿新 • • 發佈:2021-07-28
部落格園突然打不開了,奇奇怪怪的……
少寫個等號沒看出來 nm寫反了沒看出來 考完5min全拍出來了
手殘屬性加持 不對拍等於爆零
yysy,我連盧卡斯定理的存在都忘了……
發現要讓一大堆皇后能互相攻擊,它們貌似只能在同一條直線上
然後發現皇后數量較少的時候好像有特例
所以特判即可
\(O(n)\)解法需要列舉邊長,考慮如何優化
列舉邊長是省不掉的,考慮處理下柿子
- 有個式子:\(\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; }