solution

gcd+容斥

首先对于二维空间m * n:
假如m,n互质,显然对角线除两头外不经过任何一个方格交点,在这种情况下,直线与m+1条竖线有m+1个交点,与n+1条横线有n+1个交点,减去起点终点重复计算,总共有m+1+n+1-2 = m+n个交点。每两个相邻的交点都是被一个小正方形截出来的,所以直线经过m+n-1个小正方形。
假如m,n不互质,则直线在空间内部必定经过交点,于是可以分成若干个互质的小空间来计算,总共分成gcd(m, n)个,令g = gcd(m, n),经过的总方格数为g * (m / g + n / g - 1) = m + n - g,即横纵坐标相加再减去划分的互质区域数
**考虑多维空间: **
任意一个平面交出来的都是m+n - gcd(m, n) 个,两两组合,减去在这个平面上划分的互质区域数,最后加上减多了的。可以发现三维立方体交出来的小立方体数为 a + b + c - gcd(a, b) - gcd(b, c) - gcd(a, c) + gcd(a, b, c)。以此类推n维。n只有11,用一个dfs爆搜即可
代码:

/*
	code by A_Big_Jiong
	2021/4/24 
	not the best sol
*/ 
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 11, maxk = 1 << 11 + 1;
typedef long long lld;
int n, T;
int x[N], a[N], b[N]; 
lld ans = 0;
lld gcd(lld a, lld b) {
	if (b == 0)  return a;
	return !a ? b : gcd(b, a % b);
}
void dfs(int i, int d, bool sgn, int sel) {
	if (i == n + 1) {
		if (sel <= 1)  return ;
		ans += 1ll * d * (sgn ? -1 : 1);
		return ;
	}
	dfs(i + 1, d, sgn, sel);
	dfs(i + 1, gcd(d, x[i]), !sgn, sel + 1);
}
int main() {
	freopen("data10.in", "r", stdin);
	freopen("data10.out", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)  scanf("%d", &x[0]);
	scanf("%d", &T);
	while (T--) {
		ans = 0;
		for (int i = 1; i <= n; ++i)  scanf("%d", &a[i]);
		for (int i = 1; i <= n; ++i)  scanf("%d", &b[i]);
		for (int i = 1; i <= n; ++i)  x[i] = b[i] - a[i], ans += x[i];
		dfs(1, 0, true, 0);
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2021-04-26 00:04  Mcggvc  阅读(11)  评论(0编辑  收藏  举报