题目描述
就是让你计算这个东西
∑i=1n∑j=1mi2∗j2gcd(i,j)n,m≤1e6
分析
和经典的这个公式很像
∑ni=1∑mj=1gcd(i,j)
只需做一些简单的转化.
∑i=1n∑j=1mi2∗j2gcd(i,j)=∑i=1n∑j=1mi2∗j2∑d∣gcd(i,j)ϕ(d)=∑i=1n∑j=1mi2∗j2∑d∣i,d∣jϕ(d)=∑d=1nϕ(d)∑d∣ii2∑d∣jj2 (3)=∑d=1nϕ(d)∑k=1n/d(k∗d)2∑k=1m/d(k∗d)2=∑d=1nϕ(d)∗d4∑k=1n/dk2∑k=1m/dk2=∑d=1nϕ(d)∗d4n/d∗(n/d+1)∗(2∗(n/d)+1)6m/d∗(m/d+1)∗(2∗(m/d)+1)6
比赛的时候只想到了第三步以为 O(nlgn) 的复杂度已经够了哪知道交上去各种T,回去睡了一晚上之后就发现了平方和用公式计算这样就简单许多了.然后由于它是关于 n/d 的公式显然可以用分块求和将复杂度降低到 O(n−−√+m−−√)
AC code
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include<cmath>
#include <cstring>
#include <map>
#include <set>
#include <iomanip>
#include <bitset>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int MOD = 1e9+7;
const int MAX_P = 2e4+10;
const int maxn =1e6+10;
const int MAX_V = 5e5+10;
const int maxv = 1e6+10;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
int n,m;
LL phi[maxn],prime[maxn],cnt;
void phi_table() {
memset(prime,0,sizeof(prime));
cnt =0;
phi[1] = 1;
for(int i=2 ; i<maxn ; ++i)
{
if(!prime[i]){
prime[cnt++] = i;
phi[i] = i-1;
}
for(int j =0 ; j< cnt && i*prime[j] < maxn ; ++j){
prime[i*prime[j]] = 1;
if(i % prime[j])phi[i*prime[j]] = phi[i]*(prime[j]-1);
else{
phi[i*prime[j]] = phi[i]*prime[j];
break;
}
}
}
}
LL f1[maxn],f2[maxn];
LL sum[maxn];
int main() {
phi_table();
// for(int d = 1 ; d<= 100 ; ++d)
// std::cout << phi[d] << '\n';
int T;
int kase =0;
scanf("%d",&T );
sum[0] = 0;
for(LL i=1 ; i<maxn ; ++i){
sum[i] = sum[i-1]+(phi[i]*i*i %MOD )*(i*i%MOD)%MOD;
sum[i]%=MOD;
}
while (T--) {
scanf("%d%d",&n,&m );
if(n>m)swap(n,m);
LL ans =0;
for(LL d =1 ,last =1 ; d<=n ; d = last+1){
LL a = (LL)(n/d)*(n/d+1)/2*(2*(n/d)+1)/3 % MOD;
LL b = (LL)(m/d)*(m/d+1)/2*(2*(m/d)+1)/3 % MOD;
last = min(n/(n/d),m/(m/d));
ans+=((sum[last]-sum[d-1]+MOD)%MOD) *(a*b % MOD) % MOD;
ans%=MOD;
}
printf("Case #%d: %d\n",++kase,(int)ans );
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}