20180516模拟赛T1——queen

题解

这题显然是\(总方案数不可行方案数总方案数-不可行方案数\)(直接算是无规则的)。总方案数是\(n^2m^2\),于是问题就在于不可行的方案数。

若queen落在一个点上,则横竖是十分好求的(\(n+m\)),如果能求出斜的两条就完美了。

我们发现,这种方法Q的位置会加三次,于是我们可以在最后统一减\(3nm\)

然后比较困难的是求斜的边。

假定我们求从左上到右下线的总长度。钦定\(n\le m\)。于是就得到这样一张图:

绿色区域的点和竖线是等效的,主要是白色区域。

对于每一条斜线,我们发现第\(i\)线上的点的个数是\(i\),于是我们就可以很容易地得出不可行方案数的总和为,\(\sum_{i=1}^n i^2\)有于有4块(反着还有两块),故要乘4。

于是就是要快速求出\(\sum_{i=1}^n i^2\)。。\(\sum_{i=1}^n i^2 = \frac{n(n+1)(2n+1)}{6}\)由于我太菜了,只会归纳法,本想看一下如何现场手推(想看如何现场推的可以点这里)。

于是最后就是高精的问题了,可以不压位。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int width = 4;
const int mod = 1e4;

typedef long long LL;

struct HugeInt
{
	int a[50];
	int len;

	inline void clear()
	{
		memset(a, 0, sizeof(a));
		len = 0;
	}
};

HugeInt operator + (HugeInt a, HugeInt b)
{
	HugeInt c;
	c.clear();
	int maxlen = max(a.len, b.len);
	for(int i = 0; i < maxlen; ++i)
	{
		c.a[i] += a.a[i]+b.a[i];
		c.a[i+1] += c.a[i]/mod;
		c.a[i] %= mod;
	}
	c.len = maxlen;
	while(c.a[c.len])
		c.len++;
	return c;
}

HugeInt operator - (HugeInt a, HugeInt b)
{
	HugeInt c;
	c.clear();
	c.len = a.len;
	for(int i = 0; i < c.len; ++i)
	{
		c.a[i] += a.a[i]-b.a[i];
		if(c.a[i]<0)
		{
			a.a[i+1]--;
			c.a[i] += mod;
		}
	}
	while(!c.a[c.len-1] && c.len>=1)
		c.len--;
	return c;
}

HugeInt operator * (HugeInt a, HugeInt b)
{
	HugeInt c;
	c.clear();
	for(int i = 0; i < a.len; ++i)
		for(int j = 0; j < b.len; ++j)
			c.a[i+j] += a.a[i] * b.a[j];
	c.len = a.len + b.len - 1;
	for(int i = 0; i < c.len; ++i)
	{
		c.a[i+1] += c.a[i]/mod;
		c.a[i] %= mod;
	}
	while(c.a[c.len])
		c.len++;
	return c;
}

bool operator < (HugeInt a, HugeInt b)
{
	if(a.len != b.len)
		return a.len < b.len;
	else
	{
		for(int i = a.len-1; i >= 0; --i)
		{
			if(a.a[i] != b.a[i])
				return a.a[i] < b.a[i];
		}
	}
	return false;
}

HugeInt give(long long a)
{
	HugeInt re;
	re.clear();
	while(a)
	{
		re.a[re.len++] = a%mod;
		a /= mod;
	}
	return re;
}

HugeInt operator + (HugeInt a, LL b)
{
	return a + give(b);
}

HugeInt operator + (LL a, HugeInt b)
{
	return b + a;
}

HugeInt operator * (HugeInt a, LL b)
{
	return a * give(b);
}

HugeInt operator * (LL a, HugeInt b)
{
	return b * a;
}

HugeInt operator - (HugeInt a, LL b)
{
	return a - give(b);
}

HugeInt operator / (HugeInt a,LL b)
{
	HugeInt ans;
	ans.clear();
	ans=a;
	LL my=0;
	for(int i=ans.len-1; i>=0; i--)
	{
		ans.a[i]+=my;
		my=ans.a[i]%b*mod;
		ans.a[i]/=b;
	}
	while(!ans.a[ans.len-1])
		ans.len--;
	return ans;
}

void print(HugeInt a)
{
	printf("%d", a.a[a.len-1]);
	for(int i = a.len-2; i>=0; --i)
		printf("%04d", a.a[i]);
}

void solve(LL n, LL m)
{
	if(m < n)
		swap(n, m);
	HugeInt nn = give(n);
	HugeInt mm = give(m);
	print(nn*nn*mm*mm-(nn*(nn+1)*(nn*2+1)/3*2+nn*nn*2*(mm-nn-1)+(nn+mm)*nn*mm-3*nn*mm));
	puts("");
}

int main()
{
	freopen("queen.in", "r", stdin);
	freopen("queen.out", "w", stdout);
	int nmn;
	long long a, b;
	scanf("%d", &nmn);
	while(nmn--)
	{
		scanf("%lld%lld", &a, &b);
		solve(a, b);
	}
	return 0;
}
posted @ 2018-05-16 21:13  pfy_pfy  阅读(129)  评论(0编辑  收藏  举报