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;
}