2021CCPC湘潭全国邀请赛-C-Calculate

2021 CCPC 湘潭全国邀请赛-C-Calculate

水一水,题目链接(HDU 6940):这是链接

题面

You are given 4 positive integers x1,x2,y1,y2. Now you need to calculate

∑ i = x 1 x 2 ∑ j = y 1 y 2 ( ⌊ i x 1 ⌋ + ⌊ x 2 i ⌋ + ⌊ j y 1 ⌋ + ⌊ y 2 j ⌋ ) 2 \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}(\lfloor \frac{i}{x1}\rfloor+\lfloor \frac{x2}{i}\rfloor+\lfloor \frac{j}{y1}\rfloor+\lfloor \frac{y2}{j}\rfloor)^{2} i=x1x2j=y1y2(x1i+ix2+y1j+jy2)2

where ⌊x⌋ denotes the biggest integer that is not bigger than x.

The answer may be too large, so you just need to output it modulo ( 1 0 9 + 7 10^9+7 109+7).

题意

给定 4 4 4个数 x 1 , x 2 , y 1 , y 2 x1,x2,y1,y2 x1,x2,y1,y2,求上式。

思路

一、初见

首先明显可以看出上式由两种类型的部分组成:

一类是 ⌊ i x 1 ⌋ \lfloor \frac{i}{x1}\rfloor x1i,另一类是 ⌊ x 2 i ⌋ \lfloor \frac{x2}{i}\rfloor ix2

第一类

第一类经过打表可以发现规律,比如: x 1 = 4 , x 2 = 17 x1=4,x2=17 x1=4,x2=17时:

i=4  ans=1
i=5  ans=1
i=6  ans=1
i=7  ans=1
i=8  ans=2
i=9  ans=2
i=10 ans=2
i=11 ans=2
i=12 ans=3
i=13 ans=3
i=14 ans=3
i=15 ans=3
i=16 ans=4
i=17 ans=4

不难看出每 x 1 x1 x1个数 ⌊ i x 1 ⌋ \lfloor \frac{i}{x1}\rfloor x1i的值会加一。

总结出规律式子:

n n n为完整的组数, n = ( x 2 − x 2 + 1 ) / x 1 n=(x2-x2+1)/x1 n=(x2x2+1)/x1,可以得到: ( ( x 2 − x 1 + 1 ) − n ∗ x 1 ) ((x2-x1+1)-n*x1) ((x2x1+1)nx1)为末尾剩下的个数

a n s = x 1 ∗ n ∗ ( n + 1 ) 2 + ( ( x 2 − x 1 + 1 ) − n ∗ x 1 ) ∗ ( n + 1 ) ans=x1*\frac{n*(n+1)}{2}+((x2-x1+1)-n*x1)*(n+1) ans=x12n(n+1)+((x2x1+1)nx1)(n+1)

需要注意的是除数2需要使用逆元

第二类

很明显可以看出,第二类是一个典型的数论分块的形式。

数论分块模板:

int ans = 0,l = 0,r = 0;
for(l = 1; l <= n; l = r + 1) {
    r = n / (n / l);
    ans += (r - l + 1) * (n / l);
} 	
二、细思

我们对于整个式子已经有了初步的了解,那么如何处理这个复杂的式子呢?

我们最快能想到的就是展开,为了便于书写我们令 ⌊ i x 1 ⌋ = A , ⌊ x 2 i ⌋ = B , ⌊ j y 1 ⌋ = C , ⌊ y 2 j ⌋ = D \lfloor \frac{i}{x1}\rfloor=A,\lfloor \frac{x2}{i}\rfloor=B,\lfloor \frac{j}{y1}\rfloor=C,\lfloor \frac{y2}{j}\rfloor=D x1i=A,ix2=B,y1j=C,jy2=D

展开得: ∑ i = x 1 x 2 ∑ j = y 1 y 2 A 2 + B 2 + C 2 + D 2 + 2 ∗ ( A ∗ B + A ∗ C + A ∗ D + B ∗ C + B ∗ D + C ∗ D ) \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}A^2+B^2+C^2+D^2+2*(A*B+A*C+A*D+B*C+B*D+C*D) i=x1x2j=y1y2A2+B2+C2+D2+2(AB+AC+AD+BC+BD+CD)

我们逐一分析:

1、 A 2 & C 2 A^2\&C^2 A2&C2

这个部分由两个相同的第一类式子相乘构成,我们展开书写 A 2 A^2 A2得: ∑ i = x 1 x 2 ∑ j = y 1 y 2 ⌊ i x 1 ⌋ 2 \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}\lfloor \frac{i}{x1}\rfloor^2 i=x1x2j=y1y2x1i2

其实不难看出,就是第一类式子的平方,当 x 1 = 4 , x 2 = 17 x1=4,x2=17 x1=4,x2=17时,数列为: 1 , 1 , 1 , 1 , 4 , 4 , 4 , 4 , 9 , 9 , 9 , 9 , 16 , 16 1,1,1,1,4,4,4,4,9,9,9,9,16,16 1,1,1,1,4,4,4,4,9,9,9,9,16,16

同理可得:设 n n n为完整的组数, n = ( x 2 − x 2 + 1 ) / x 1 n=(x2-x2+1)/x1 n=(x2x2+1)/x1,可以得到: ( ( x 2 − x 1 + 1 ) − n ∗ x 1 ) ((x2-x1+1)-n*x1) ((x2x1+1)nx1)为末尾剩下的个数

a n s = x 1 ∗ n ( n + 1 ) ( 2 n + 1 ) 6 + ( ( x 2 − x 1 + 1 ) − n ∗ x 1 ) ∗ ( n + 1 ) ∗ ( n + 1 ) ans=x1*\frac{n(n+1)(2n+1)}{6}+((x2-x1+1)-n*x1)*(n+1)*(n+1) ans=x16n(n+1)(2n+1)+((x2x1+1)nx1)(n+1)(n+1)

2、 B 2 & D 2 B^2\&D^2 B2&D2

这个部分由两个相同的第二类式子相乘构成,我们展开书写 B 2 B^2 B2得: ∑ i = x 1 x 2 ∑ j = y 1 y 2 ⌊ x 2 i ⌋ 2 \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}\lfloor \frac{x2}{i}\rfloor^2 i=x1x2j=y1y2ix22

稍微对数论分块部分进行修改:

int ans = 0,l = 0,r = 0;
for(l = 1; l <= n; l = r + 1) {
    r = n / (n / l);
    ans += (r - l + 1) * (n / l)* (n / l);
} 	

== ∑ i = x 1 x 2 ∑ j = y 1 y 2 ⌊ x 2 i ⌋ 2 \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}\lfloor \frac{x2}{i}\rfloor^2 i=x1x2j=y1y2ix22不等于 ∑ j = y 1 y 2 ( ∑ i = x 1 x 2 ⌊ x 2 i ⌋ ) ∗ ( ∑ i = x 1 x 2 ⌊ x 2 i ⌋ ) \sum_{j=y1}^{y2}(\sum_{i=x1}^{x2}\lfloor \frac{x2}{i}\rfloor)*(\sum_{i=x1}^{x2}\lfloor \frac{x2}{i}\rfloor) j=y1y2(i=x1x2ix2)(i=x1x2ix2)==此处不做赘述

注意不要漏了把最后的结果乘上 ( y 2 − y 1 + 1 ) (y2-y1+1) (y2y1+1)[由于有 ∑ j = y 1 y 2 \sum_{j=y1}^{y2} j=y1y2]

3、 A ∗ B & C ∗ D A*B\&C*D AB&CD

这两个部分是由变量相同的一个第一类式子和一个第二类式子相乘得到,展开 A ∗ B A*B AB得: ∑ i = x 1 x 2 ∑ j = y 1 y 2 ⌊ i x 1 ⌋ ⌊ x 2 i ⌋ \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}\lfloor \frac{i}{x1}\rfloor\lfloor\frac{x2}{i}\rfloor i=x1x2j=y1y2x1iix2

这个式子的处理相对比较复杂,我们列表可以更好的理解,如 x 1 = 4 , x 2 = 17 x1=4,x2=17 x1=4,x2=17时:

i=4  left=1 right=4
i=5  left=1 right=3
i=6  left=1 right=2
i=7  left=1 right=2
i=8  left=2 right=2
i=9  left=2 right=1
i=10 left=2 right=1
i=11 left=2 right=1
i=12 left=3 right=1
i=13 left=3 right=1
i=14 left=3 right=1
i=15 left=3 right=1
i=16 left=4 right=1
i=17 left=4 right=1

我们前面可以很好的求出第一类式子的前缀和和第二类式子的分块区间,那么我们就有了一个大胆的想法:由于某一个分块区间中的 r i g h t right right恒定,且起止位置已知,我们可以用这个恒定值乘以 l e f t left left在此分块区间中的差分值,如: r i g h t = 2 right=2 right=2时,左侧的和 S U M = s u m ( 9 ) − s u m ( 8 − 1 ) = ( 1 + 1 + 1 + 1 + 2 ) − ( 1 + 1 + 1 ) SUM=sum(9)-sum(8-1)=(1+1+1+1+2)-(1+1+1) SUM=sum(9)sum(81)=(1+1+1+1+2)(1+1+1) r i g h t ∗ s u m right*sum rightsum即为此区间的结果

同样不要忘了乘上 ( y 2 − y 1 + 1 ) (y2-y1+1) (y2y1+1)

4、其他部分

其他部分都是形如 A ∗ D A*D AD的式子,此类式子是有变量不同的一个第一类式子和一个第二类式子相乘得到,展开 A ∗ D A*D AD ∑ i = x 1 x 2 ∑ j = y 1 y 2 ⌊ i x 1 ⌋ ⌊ y 2 j ⌋ \sum_{i=x1}^{x2}\sum_{j=y1}^{y2}\lfloor \frac{i}{x1}\rfloor\lfloor\frac{y2}{j}\rfloor i=x1x2j=y1y2x1ijy2

这类式子有一个特点就是可以分别计算第一类式子和第二类式子并相乘得到结果,证明过程略。

三、完整AC代码(有点乱)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7;

ll fenkuai1(ll lower, ll high)
{
	ll ans = 0;
	for (ll l = lower, r = 0; l <= high; l = r + 1)
	{
		r = high / (high / l) % mod;
		ans = (ans + (r - l + 1) % mod * (high / l) % mod) % mod;
	}
	return ans % mod;
}

ll fenkuai2(ll lower, ll high)
{
	ll ans = 0;
	for (ll l = lower, r = 0; l <= high; l = r + 1)
	{
		r = high / (high / l) % mod;
		ans =
			(ans % mod + (r - l + 1) % mod * (high / l) % mod * (high / l) % mod) %	mod;
	}
	return ans % mod;
}

ll solve1(ll x1, ll x2)
{
	ll n = (x2 - x1 + 1) % mod / x1 % mod;
	return (((x1 * n) % mod * (n + 1) % mod * 500000004) % mod +
			(((x2 - x1 + 1) % mod - n * x1 % mod) % mod * (n + 1) % mod) % mod) % mod;
}

ll solve2(ll x1, ll x2)
{
	ll n = (x2 - x1 + 1) / x1 % mod;
	//	cout<<n<<' '<<n%mod*(n+1)%mod*(2*n+1)%mod*166666668%mod<<' '<<n * (n +
	//1) % mod * ((2 * n + 1) % mod) % mod * 166666668 %mod<<endl;
	return (((x1 * n) % mod * (n + 1) % mod * (2 * n % mod + 1) % mod *
			 166666668) %
				mod +
			(((x2 - x1 + 1) % mod - n * x1 % mod) % mod * (n + 1) % mod *
			 (n + 1) % mod) %
				mod) %
		   mod;
}
//((x2-x1+1)%mod-n*x1%mod)%mod*(n+1)%mod)%mod

ll solve3(ll lower, ll high)
{
	ll ans = 0;
	for (ll l = lower, r = 0; l <= high; l = r + 1)
	{
		r = high / (high / l) % mod;
		//	    cout<<l<<' '<<r<<' '<<(high / l)<<'
		//'<<solve1(lower,r)-solve1(lower,l-1)<<' '<<solve1(lower,r)<<endl;
		if (l > lower)
			ans = (ans % mod +
				   (high / l) % mod *
					   (solve1(lower, r) % mod - solve1(lower, l - 1) % mod) % mod) %
				  mod;
		else
			ans =
				(ans % mod + (high / l) % mod * (solve1(lower, r) % mod) % mod) % mod;
		//	    cout<<(r - l + 1) *(high /
		//l)*(solve1(lower,r)-solve1(lower,l-1))<<endl;
		while (ans < 0)
			ans += mod;
	}

	return ans % mod;
}
int main()
{
	ll x1, x2, y1, y2, A, B, C, D;
	int t;
	cin >> t;
	while (cin >> x1 >> x2 >> y1 >> y2)
	{
		ll ans = 0;
		A = solve1(x1, x2) % mod;
		B = fenkuai1(x1, x2) % mod;
		C = solve1(y1, y2) % mod;
		D = fenkuai1(y1, y2) % mod;
		//		cout<<solve2(x1,x2)*(y2-y1+1)%mod<<endl;
		//		cout<<fenkuai2(x1,x2)*(y2-y1+1)%mod<<endl;
		//		cout<<solve2(y1,y2)*(x2-x1+1)%mod<<endl;
		//		cout<<fenkuai2(y1,y2)*(x2-x1+1)%mod<<endl;
		//
		//		cout<<solve3(x1,x2)*(y2-y1+1)%mod<<endl;
		//		cout<<A*C%mod<<endl;
		//		cout<<A*D%mod<<endl;
		//		cout<<B*C%mod<<endl;
		//		cout<<B*D%mod<<endl;
		//		cout<<solve3(y1,y2)*(x2-x1+1)%mod<<endl;
		ans = (ans + fenkuai2(x1, x2) % mod * (y2 - y1 + 1) % mod) % mod;
		ans = (ans + solve2(x1, x2) % mod * (y2 - y1 + 1) % mod) % mod;
		ans = (ans + fenkuai2(y1, y2) % mod * (x2 - x1 + 1) % mod) % mod;
		ans = (ans + solve2(y1, y2) % mod * (x2 - x1 + 1) % mod) % mod;
		ans = (ans + solve3(x1, x2) % mod * (y2 - y1 + 1) % mod) % mod;
		ans = (ans + A * C % mod) % mod;
		ans = (ans + A * D % mod) % mod;
		ans = (ans + B * C % mod) % mod;
		ans = (ans + B * D % mod) % mod;
		ans = (ans + solve3(y1, y2) % mod * (x2 - x1 + 1) % mod) % mod;
		ans = (ans + solve3(x1, x2) % mod * (y2 - y1 + 1) % mod) % mod;
		ans = (ans + A * C % mod) % mod;
		ans = (ans + A * D % mod) % mod;
		ans = (ans + B * C % mod) % mod;
		ans = (ans + B * D % mod) % mod;
		ans = (ans + solve3(y1, y2) % mod * (x2 - x1 + 1) % mod) % mod;
		cout << ans << endl;
	}
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值