有这样一个有关最大公约数的函数:
函数 f(x, y):
{ c=0 当 y>0: { c +=1 t = x % y x = y y = t } 返回 c * x * x}
给出三个正整数n,m,p,你需要计算:
∑i=1n∑j=1m?i?jf(i,j)
对p取模的结果。
1 #include <stdio.h> 2 #include <iostream> 3 #include <stack> 4 #include <algorithm> 5 #include <cstring> 6 #include <vector> 7 #include <cmath> 8 #include <cctype> 9 using namespace std; 10 typedef long long ll; 11 void in(int& n){scanf("%d",&n);} 12 void in(ll& n){scanf("%I64d",&n);} 13 const int N = 700; 14 int gcd[N][N],num[N][N]; 15 int n,m,p; 16 ll calc(ll x,ll y,ll tot,ll cnt)//tot 个数 cnt 分母 17 { 18 ll ans = (tot+1)*(x*y)+(tot+1)*tot/2*(y*y);//总和 19 ll rd = y*y%cnt; 20 ll ra = y*x%cnt; 21 ll res = 0; //余数 22 /*for(int i=0;i<=tot;++i){res+=(i*rd+ra)%cnt;} 23 return (ans-res)/cnt%p; 24 */ //复杂度太高 25 for(int i=0;i<cnt;++i){ 26 res += (rd*i+ra)%cnt; 27 } 28 res = tot/cnt*res; 29 for(int i=0;i<=tot%cnt;++i) 30 { 31 res += (rd*i+ra)%cnt; 32 } 33 return (ans-res)/cnt%p; 34 } 35 void init() 36 { 37 for(int i=0;i<N;i++) 38 for(int j=0;j<N;j++) 39 if(i==0||j==0) gcd[i][j]=i+j; 40 else if(i<j) gcd[i][j] = gcd[i][j%i]; 41 else gcd[i][j] = gcd[i%j][j]; 42 for(int i=1;i<N;i++) 43 for(int j=0;j<i;j++) 44 { 45 if(j==0) num[i][j] = 1; 46 else num[i][j] = num[j][i%j] +1; 47 } 48 } 49 int main() 50 { 51 init(); 52 int T; 53 scanf("%d",&T); 54 while(T--) 55 { 56 int ans = 0; 57 scanf("%d%d%d",&n,&m,&p); 58 for(int i=1;i<=m;i++) 59 for(int j=0;j<i&&j<=n;j++) 60 { 61 ans+=calc(j/gcd[i][j],i/gcd[i][j],(n-j)/i,num[i][j]); 62 ans%=p; 63 } 64 printf("%d\n",ans); 65 } 66 return 0; 67 }
AC代码
因为计算被m限制 变成了m个等差数列 求数列每一项/cnt 之和
但是 但是 裸计算余数复杂度太大
所以 就是现场 看懂了题。。。也A不掉。。。。然后贴的这个余数 转化为cnt的计算方式。。。
肯定是以cnt长度为循环。。。tot/cnt个循环
余下的tot%cnt 再求一次即可
那么复杂度就降下来了
时间: 2024-11-06 11:03:53