11.10 考试 T1

给你一个 (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;
}
原文地址:https://www.cnblogs.com/genshy/p/13956349.html