BZOJ 2956 模积和

题目链接:模积和

  这种有模运算的题一般都要把取模运算给去掉,改成除法取下整的模式。即\(a\bmod b=a-\lfloor \frac{a}{b} \rfloor b\)

  然后我们先把\(i=j\)的也统计进答案,最后再减去即可。接下来就是推式子时间(\(n \le m\)):

\begin{aligned}
&\sum_{i=1}^n\sum_{j=1}^m(n \bmod i)(m \bmod j) \\
=&\sum_{i=1}^n(n \bmod i)\sum_{j=1}^m(m \bmod j) \\
=&\sum_{i=1}^n(n-i\lfloor \frac{n}{i} \rfloor)\sum_{j=1}^m(m-j\lfloor \frac{m}{j} \rfloor) \\
=&(n^2-\sum_{i=1}^ni\lfloor \frac{n}{i} \rfloor)(m^2-\sum_{i=1}^mi\lfloor \frac{m}{i} \rfloor)
\end{aligned}

\begin{aligned}
&\sum_{i=1}^n(n \bmod i)(m \bmod i) \\
=&\sum_{i=1}^n(n-i\lfloor \frac{n}{i} \rfloor)(m-i\lfloor \frac{m}{i} \rfloor) \\
=&n^2m-m\sum_{i=1}^ni\lfloor \frac{n}{i} \rfloor-n\sum_{i=1}^ni\lfloor \frac{m}{i} \rfloor+\sum_{i=1}^n\lfloor \frac{n}{i} \rfloor\lfloor \frac{m}{i} \rfloor i^2
\end{aligned}

  然后分块计算即可。上下两个式子一减就是答案。

  下面贴代码:

#include<cstdio>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define mod 19940417
#define llg long long
#define min(a,b) (a<b?a:b)

const int n6=7776;
int n,m,a[3];

llg S(int x){return (1ll*x*(x+1)>>1)%mod;}
llg S2(int x){
	a[0]=x,a[1]=x+1,a[2]=2*x+1;
	for(int i=0;i<3;i++) if(a[i]%2==0){a[i]/=2;break;}
	for(int i=0;i<3;i++) if(a[i]%3==0){a[i]/=3;break;}
	return 1ll*a[0]*a[1]%mod*a[2]%mod;
}

llg work(int x,int y){
	llg now=0;
	for(int i=1,nt;i<=x;i=nt+1)
		nt=min(y/(y/i),x),now+=1ll*(y/i)*(S(nt)-S(i-1));
	return now%mod;
}

int main(){
	File("a");
	scanf("%d %d",&n,&m);
	if(n>m) n^=m^=n^=m;
	llg s1=work(n,n),ans;
	ans=(1ll*n*n-s1)%mod*(1ll*m*m%mod-work(m,m))%mod;
	ans+=s1*m+work(n,m)*n; ans%=mod;
	ans-=1ll*n*n%mod*m; ans%=mod;
	for(int i=1,nt;i<=n;i=nt+1){
		nt=min(n/(n/i),m/(m/i));
		ans-=(S2(nt)-S2(i-1))*(m/i)%mod*(n/i);
		ans%=mod;
	}
	printf("%lld",(ans+mod)%mod);
	return 0;
}
posted @ 2017-05-05 11:11 lcf2000 阅读(...) 评论(...) 编辑 收藏