Description:
1<=T<=10000,1<=n<=4000
题解:
好久没有比赛时切这么恶心的数论题了。
显然的想法是枚举直线的斜率,再把这条直线塞到矩形里,平行于坐标轴的直线特判一下就行了。
枚举斜率就是枚举个i,j,斜率就是j/i,保证(gcd(i, j) =1)就不会重复,斜率为负的是一样的,最后乘一个2即可。
最后一个问题这条直线能塞到多少个地方。可以这么想:这条直线占了一个i*j的矩形,那就有(n-i+1)*(m-j+1)个位置可以塞。
但是这样显然是错的,因为会出现下图这种情况:
这两条直线存在于两个不同的矩形中,但是实际上是一条直线。
于是我们会想到枚举矩形的左上角,只要没有矩形以左上角为右下角,那么这个矩形就是合法的。
总结一下可得:
Ans=∑n−1i=1∑m−1j=1[gcd(i,j)=1]∗∑n−ix=1∑m−jy=1[x<=i or y<=j]
有gcd,就可以反演了。
为了方便,接下来的n,m都减了1。
=∑ni=1∑mj=1∑d|gcd(i,j)μ(d)∗∑n−i+1x=1∑m−j+1y=1[x<=i or y<=j]
∑nd=1μ(d)∗∑⌊nd⌋i=1∑⌊md⌋j=1∑n−i∗d+1x=1∑m−j∗d+1y=1[x<=i∗d or y<=j∗d]
容斥一下,易得:
=∑nd=1μ(d)∗∑⌊nd⌋i=1∑⌊md⌋j=1(∑n−i∗d+1x=1[x<=i∗d]∗(m−j∗d+1))+(∑m−j∗d+1y=1[y<=j∗d]∗(n−i∗d+1)))−(∑n−i∗d+1x=1∑m−j∗d+1y=1[x<=i∗d and y<=j∗d])
=∑nd=1μ(d)∗(∑⌊nd⌋i=1∑n−i∗d+1x=1[x<=i∗d]∗∑⌊md⌋j=1(m−j∗d+1))+(∑⌊md⌋j=1∑m−j∗d+1y=1[y<=j∗d]∗∑⌊nd⌋i=1(n−i∗d+1))−((∑⌊nd⌋i=1∑n−i∗d+1x=1[x<=i∗d]∗(∑⌊md⌋j=1∑m−j∗d+1y=1[y<=j∗d])
于是暴力枚举d,可以利用等差数列求和快速算出所需的东西。
时间复杂度:O(T∗n)
这题是2016计蒜客联想的显示屏校准(困难)的一个部分分,实际上式子还可以化简,一个查询是O(n√),在这里不再继续推了。
Code:
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int mo = 1 << 30;
const int N = 4000;
int T, n, m, p[N], mu[N + 5];
bool bz[N + 5];
ll ans;
void Build() {
mu[1] = 1;
fo(i, 2, N) {
if(!bz[i]) p[++ p[0]] = i, mu[i] = -1;
fo(j, 1, p[0]) {
int k = i * p[j];
if(k > N) break;
bz[k] = 1;
if(i % p[j] == 0) {
mu[k] = 0; break;
}
mu[k] = -mu[i];
}
}
}
int main() {
Build();
for(scanf("%d", &T); T; T --) {
scanf("%d %d", &n, &m);
if(n > m) swap(n, m);
n --; m --;
ans = 0;
fo(i, 1, n) if(mu[i] != 0) {
int sf, sg;
int c = n / i, c2 = (n + 1) / 2 / i, s;
sf = (1 + c2) * c2 / 2 * i;
sf += (n + 1) * (c - c2) - (c2 + 1 + c) * (c - c2) / 2 * i;
c = m / i, c2 = (m + 1) / 2 / i, s;
sg = (1 + c2) * c2 / 2 * i;
sg += (m + 1) * (c - c2) - (c2 + 1 + c) * (c - c2) / 2 * i;
int s1 = (n + 1) * (n / i) - (n / i) * (n / i + 1) * i / 2;
int s2 = (m + 1) * (m / i) - (m / i) * (m / i + 1) * i / 2;
ans += mu[i] * (sf * s2 + sg * s1 - sf * sg);
}
ans *= 2; ans += n + m + 2;
ans = (ans % mo + mo) % mo;
printf("%lld\n", ans);
}
}
本文介绍了一种解决特定数论问题的方法,通过枚举直线斜率并利用欧拉函数简化计算过程,最终给出了一种时间复杂度为O(T*n)的有效解决方案。
942

被折叠的 条评论
为什么被折叠?



