[BZOJ2693]jzptab

【题目描述】

为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中的i行的j列写着数lcm(i,j)。crash表格里所有数的和mod100000009的值。

【输入格式】

第一行输入T,表示数据组数。接下来的T行,每行输入N和M

【输出格式】

对于每个询问,输出表格中所有数的和mod100000009的值

【样例输入】

1
4 5

【样例输出】

122

【提示】

T<=10000;N,M<=10000000

先附一个链接:

https://www.cnblogs.com/yoyoball/p/8231397.html

我是直接枚举i和i的倍数j计算f()的,可以证明这样只有O(nlogn)

但是链接中运用积性函数性质用线性筛更好

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long lol;
 8 int Q[10001][2],Mod=100000009,inv2,N,tot,n,m;
 9 int f[10000005],ans,mu[10000005],prime[5000005];
10 bool vis[10000005];
11 int get_sum(int x,int y)
12 {
13   int s1,s2;
14   s1=(1ll*(1+x)*x/2)%Mod;
15   s2=(1ll*(1+y)*y/2)%Mod;
16   return 1ll*s1*s2%Mod;
17 }
18 void pre()
19 {int i,j;
20   mu[1]=1;
21   for (i=2;i<=N;i++)
22     {
23       if (vis[i]==0)
24     {
25       ++tot;
26       prime[tot]=i;
27       mu[i]=-1;
28     }
29       for (j=1;j<=tot;j++)
30     {
31       if (1ll*i*prime[j]>N) break;
32       vis[i*prime[j]]=1;
33       if (i%prime[j]==0)
34         {
35           mu[i*prime[j]]=0;
36           break;
37         }
38       else mu[i*prime[j]]=-mu[i];
39     }
40     }
41   for (i=1;i<=N;i++)
42     {
43       for (j=1;j<=N;j++)
44     {
45       if (1ll*i*j>N) break;
46       f[i*j]+=i*mu[i];
47       f[i]=(f[i]+Mod)%Mod;
48     }
49     }
50   for (i=1;i<=N;i++)
51     f[i]=(1ll*f[i]*i%Mod+f[i-1])%Mod;
52 }
53 int main()
54 {
55   int T,i,j,pos;
56   cin>>T;
57   for (i=1;i<=T;i++)
58     {
59       scanf("%d%d",&Q[i][0],&Q[i][1]);
60       if (Q[i][0]>Q[i][1]) swap(Q[i][0],Q[i][1]);
61       N=max(N,Q[i][0]);
62     }
63   pre();
64   for (j=1;j<=T;j++)
65     {
66       ans=0;
67       n=Q[j][0],m=Q[j][1];
68       for (i=1;i<=n;i=pos+1)
69     {
70       pos=min(n/(n/i),m/(m/i));
71       ans=(ans+1ll*get_sum(n/i,m/i)*((f[pos]-f[i-1]+Mod)%Mod)%Mod)%Mod;
72     }
73       printf("%d\n",ans);
74     }
75 }

 

posted @ 2018-01-24 11:32  Z-Y-Y-S  阅读(299)  评论(2编辑  收藏  举报