雾
给你一个 (n*m) 的棋盘,放上两个不同的皇后,让你求出互相攻击的方案数。
攻击规则和国际象棋一样,输出对 (1e8+7) 取模的结果。
(n,mleq 10^9)
soultion
数学计数题,颓柿子。
我们可以分三种情况讨论。
- 两个皇后在同一行的情况,每一行共有 (m*(m-1)) 种方案数,共有 (n) 行,总方案数为 (n*m*(m-1))
- 同一列的情况同理,共有 (m*n*(n-1)) 种方案。
- 同一个对角线的情况,则有 (displaystyle2 imes (2 imes sum_{i=1}^{n-1} i imes (i-1) + (m-n+1) imes n(n-1)))
对于第三种情况我们可以 (O(n)) 的求出来。还是不够,继续化简柿子可得。
对于 (displaystylesum_{i=1}^{n-1} i imes (i-1) = sum_{i=1}^{n-1} i^2 - sum_{i-1}^{n-1} i)
然后根据公式 (displaystylesum_{i=1}^{n}i = {i imes (i+1)over 2}), (displaystylesum_{i=1}^{n}i^2 = {n imes(n+1) imes(2n+1)over 6}). 代入可得。
(displaystylesum_{i=1}^{n-1} i imes (i-1) = {n imes(n-1) imes(2n-1)over 6} - {n imes (n-1)over 2})(={n imes (n-1) imes(n-2)over 3})
继续代入可得:
(原式 = 2 imes ({n imes(n-1) imes(2n-4)over 3} + (m-n+1) imes n(n-1)) = {2n(n-1)(3m-n-1)over3})
然后就可以 (O(1)) 的来求了。
code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int p = 1e8+7;
int n,m,ans;
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int ksm(int a,int b)
{
int res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
signed main()
{
// freopen("wu.in","r",stdin);
// freopen("wu.out","w",stdout);
while(1)
{
n = read(); m = read();
if(n == 0 && m == 0) break;
ans = n * (n-1) * m ;
ans = (ans + m * (m-1) * n);
if(n > m) swap(n,m);
ans = ans + 2 * n * (n-1) * (3 * m - n - 1)/3;
cout<<ans<<endl;
}
return 0;
}