uva11538 Chess Queen(组合问题)

题意:

给定一个棋盘,在棋盘上放两个皇后(一白一黑),求使得两个皇后相互攻击(在一行、一列或对角线)的方案数。行n,列m。
思路:组合问题。
先按行看:先放其中一个,有m种选择,另一个有(m-1)种选择,一共有n行,所以按行看有n*m*(m-1)种方案。
按列看: 先放其中一个,有n种选择另一个有(n-1)种选择,一共有m列,所以按列看有m*n*(n-1)种方案。
比较难的是斜边,因为是对称的,先考虑一边,令少的那边作为行(即n<=m)可以发现,斜边长度依次为1,2.......n-2,n-1,n,n,n.......n-1,n-2...........2,1。并且一共有(m-n+1)个n,1到n-1各有两个。(当然,长度为1的不能要)
(m-n+1)个n的方案数:(m-n+1)*n*(n-1)
1到n-1的方案数: 2*i*(i-1)=2*i^2-i
利用等差数列前n项和及n^2的前n项和( n(n+1)(2n+1)6)可将1到n-1方案数合并为
n(n-1)(2n-1)6 n(n-1)2 再×2        //注意这里是前n-1项和,同时1^2-1=0所以从1开始没关系。
所以斜边的总方案数为:( (m-n+1)个n 的方案数+1到n-1的方案数)*2  //还有另一方向的斜边故*2
所以总方案数为:行+列+斜边(遵循加法原理)

ps:

如果1到n-1用循环来求的话,似乎会tle,所以要尽可能地整合公式。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
	long long n,m;//都用long long 较好
	while(scanf("%lld%lld",&n,&m)==2)
	{
		if(n==0 && m==0){break;}
		if(n>m){
			swap(m,n);
		}
	/*	long long hang=n*m*(m-1);//之前想暴力,结果tle
		long long lie=m*n*(n-1);
		long long xiebian=(m-n+1)*n*(n-1)+((n*(n-1)*(2*n-1))/3)-2-((n-2)*(n+1));*/
		/*int n1=n-1;
		while(n1>=2){//之前想暴力,结果tle
			xiebian+=2*n1*(n1-1);
			n1--;
		}*/
		
		//xiebian*=2;
		printf("%lld\n",m*n*(n+m-2)+2*(n*(n-1)*(3*m-n-1)/3));//m*n*(n+m-2)为行列的整合,2*(n*(n-1)*(3*m-n-1)/3)为斜边的化简
	}                                                          
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30684235/article/details/79871963