BZOJ 2956 模积和

Description

求$$ sum_{i=1}^{n} sum_{j=1}^{m} lbrack i eq j brack(n ; mod; i)(m ; mod ; j)$$。

Input

第一行两个数(n,m)

Output

一个整数表示答案(mod;19940417)的值。

Sample Input

3 4

Sample Output

1

Hint

数据规模和约定

对于(100\%)的数据(n,m le 10^{9})

补数论中。
这题我们要从模的本质出发:$$a ; mod ; b = a - b imes lfloor frac{a}{b} floor$$
我们首先不考虑(i eq j)条件,单独对(i)(j)讨论,我们可以得到$$sum_{i = 1}^{n}n;mod;i=sum_{i = 1}^{n}n-i imes lfloor frac{n}{i} floor$$
化简一下,可以得到$$sum_{i = 1}^{n}n-i imes lfloor frac{n}{i} floor = n{2}-sum_{i=1}{n}i lfloor frac{n}{i} floor$$
由与(lfloor frac{n}{i} floor)不同的只有(sqrt{n})个,这个式子可以(O(sqrt{n}))计算。对于(i,j)分别做一遍相乘起来即可。
对于(i=j)的部分,单独拿出来减去贡献即可。我们用类似的方法,即求$$sum_{i=1}^{min(n,m)}(n;mod;i)(m;mod;i)$$
然后跟之前一样的处理方法化为求$$sum_{i=1}^{min(n,m)}(n-i imes lfloor frac{n}{i} floor)(m - i imes lfloor frac{m}{i} floor)$$
稍微化简一下就可以也(sqrt{n})分块了$$sum_{i=1}^{min(n,m)}(nm - mi lfloor frac{n}{i} floor - ni lfloor frac{m}{i} floor + i^{2}lfloor frac{m}{i} floor lfloor frac{n}{i} floor)$$

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

typedef long long ll;
#define rhl (19940417)

inline ll sum(ll a,ll b) { return (((ll)(a+b)*(ll)(b-a+1))>>1)%rhl; }

inline ll calc(ll n,ll m)
{
	ll ret = n*m%rhl;
	ll pos;
	for (ll i = 1;i <= m;i = pos+1)
	{
		pos = min(m,n/(n/i));
		(ret -= sum(i,pos)*(n/i)%rhl)%=rhl;
	}
	return ret;
}

inline ll pre(ll n)
{
	ll a = n,b = n+1,c = 2*n+1;
	return a*b%rhl*c%rhl*3323403%rhl;
}

int main()
{
	freopen("2956.in","r",stdin);
	freopen("2956.out","w",stdout);
	ll n,m;
	scanf("%lld %lld",&n,&m);
	if (n > m) swap(n,m);
	ll ans1 = calc(n,n),ans2 = calc(m,m);
	ll ans = (ans1*ans2%rhl+rhl)%rhl;
	ll pos = 1;
	for (ll i = 1;i <= n;i = pos+1)
	{
		pos = min(n,min(n/(n/i),m/(m/i)));
		(ans -= n*m%rhl*(ll)(pos-i+1))%=rhl;
		(ans += sum(i,pos)*(m*(n/(ll)i)%rhl+n*(m/(ll)i)%rhl)%rhl)%=rhl;
		(ans -= (pre(pos)-pre(i-1))%rhl*(n/(ll)i)%rhl*(m/(ll)i)%rhl)%=rhl;
	}
	printf("%lld",(ans%rhl+rhl)%rhl);
	fclose(stdin); fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/mmlz/p/4424801.html