首页 > 代码库 > hdu5970

hdu5970

真是怀疑当初合肥赛区怎么考这么差的……

首先根据辗转相除法可知f(i,j)=f(i+j*k,j)

于是我们可以先于处理出f(i,j) (j<=666,i<=j),当确定i,j时c也确定

技术分享

(x=gcd(i,j))可见,当确定了i,j,k后,后面p的求和就是一个等差数列的求和

c是logm级的所以总复杂度就是O(T*m^2*logm)

技术分享
 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 int f[670][670],c[670][670],n,m,p;
 6 int get(int x,int y,int &f,int &c)
 7 {
 8     int t; c=0;
 9     while (y)
10     {
11         c++;
12         t=x%y; x=y; y=t;
13     }
14     f=c*x*x;
15 }
16 
17 int main()
18 {
19     int cas;
20     scanf("%d",&cas);
21     for (int j=1; j<=666; j++)
22         for (int i=1; i<=j; i++)
23             get(i,j,f[i][j],c[i][j]);
24     while (cas--)
25     {
26         scanf("%d%d%d",&n,&m,&p);
27         ll ans=0;
28         for (int j=1; j<=m; j++)
29             for (int i=1; i<=j&&i<=n; i++)
30                 for (int k=0; k<c[i][j]; k++)
31                 {
32                     if (i+k*j>n) break;
33                     ll b=(i+j*k)*j/f[i][j];
34                     ll d=c[i][j]*j*j/f[i][j];
35                     ll t=(n-(i+j*k))/(c[i][j]*j)+1;
36                     ans=(ans+b*t%p+(t-1)*t/2%p*d%p)%p;
37                 }
38         printf("%lld\n",ans);
39     }
40 }
View Code

 

hdu5970