ACM湘潭市2018邀请赛 K题-2018

本文解析了一道ACM竞赛题,通过集合论思想巧妙地解决了两个区间内任意数相乘得到2018倍数的问题,区分了2018的倍数、因子以及组合方式,提供了清晰的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=6286

题目大意是,给出两个区间,A,B。从两个区间中各自任意取出一个数(a_{i},b_{j}),使得a_{i}*b_{j}是2018的倍数。

既然要组合出2018的倍数,就先要知道2018有些什么因子,很容易得出,2018只有1、2、1009、2018四个因数。

那么组合2018的方式也是有一个直接思路的,若x是2018的倍数,那么x的因子里面必须有2和1009。

 

在组合出2018的倍数时,常常有多算少算的情况。

最为根本的原因就是,组合时可以用2*1009或者2018*任何数来组合。在计算的过程中,总是考虑不清楚,,不过从集合的方向去思考就会变的明了。

令题目给出的 a~b 间的数集合为 A  ,c~d 间的数为集合B 。

另外,A的子集 A_{2}表示 集合A中 2 的倍数。  A_{8}表示集合A 中2018的倍数 A_{9}代表 A 中1009的倍数。

同样,对B 也有B_{2}  B_{9}   B_{8}

既然2018的倍数本身很容易混淆,那么我们就分两种情况。A集合中选出 ai  B 集合中选出 bj ,两种情况如下:

一、ai  bj 是2018的倍数。

二、ai bj 都不是2018的倍数 。

 

首先看ai bj 是2018倍数的情况。如果 ai 是2018的倍数,那么 bj 可以取任何数,这里就有 \left | B \right |*\left |A_{8} \right | 种,这里的\left | B \right |代表集合 B 的总数。

同样,如果 bj 是2018的倍数,ai 就可以是任何数那么这里就有\left | A \right |*\left |B_{8} \right | 中。这就是两个数 ai  bj 分别为2018的倍数的种类数,结果Sum=\left | A \right |*\left | B_{8} \right |+\left | B \right |*\left |A_{8} \right |

这里我们已经把  ai bj 都为2018的倍数的可能性包含在了这两种情况中。而且重复算了两次,所以最终结果要减去一次。ai bj同时为2018的倍数种类数为  \left | A_{8} \right |*\left |B_{8} \right |。所以最后的结果应该为Sum=\left | A \right |*\left | B_{8} \right |+\left | B \right |*\left |A_{8} \right |-\left | A_{8} \right |*\left | B_{8} \right |

再来看第二种情况

ai 和 bj 都不是2018的倍数,当然我们说的是为1009或者2的倍数,但不是2018的倍数的数。

这里面又可以分为两种子情况 

1、ai 为1009但不为2018的倍数,bj 为2但不为1009的倍数。

2、反过来ai 为2但不为1009的倍数,bj为1009但不为2018的倍数.

其实分别可以用两个式子来表示,   

1、(\left | A_{9} \right |-\left | A_{8} \right |)*(\left | B2 \right |-\left | B8 \right |) 这个式子是很好理解的,第一项代表ai 为1009但不为2018的倍数,第二项代表bj 为2但不为1009的倍数。

2、(\left | B_{9} \right |-\left | B_{8} \right |)*(\left | A_{2} \right |-\left | A_{8} \right |) 同理。

这两种肯定是互斥独立的,同样,这里所有的情况和为Sum2=(\left | A_{9} \right |-\left | A_{8} \right |)*(\left | B2 \right |-\left | B8 \right |)+(\left | B_{9} \right |-\left | B_{8} \right |)*(\left | A_{2} \right |-\left | A_{8} \right |)种,这里所有的情况肯定和第一种2018的情况没有任何重复。因为这里的每一项都去除了2018的倍数。

那么最后的解应该为,SUM=\left | A \right |*\left | B_{8} \right |+\left | B \right |*\left |A_{8} \right |-\left | A_{8} \right |*\left | B_{8} \right |+(\left | A_{9} \right |-\left | A_{8} \right |)*(\left | B2 \right |-\left | B8 \right |)+(\left | B_{9} \right |-\left | B_{8} \right |)*(\left | A_{2} \right |-\left | A_{8} \right |)

看上去这个公式又臭又长,但是其实每一项都非常好算的。

下面是代码:

#include<iostream>

using namespace std;

typedef long long ll;

int main(){
	ll sum,a,b,c,d;
	
	
	
	sum=0;
	while(cin>>a>>b>>c>>d){
	
	ll a2=b/2-(a-1)/2;
	ll a8=b/2018-(a-1)/2018;
	ll a9=b/1009-(a-1)/1009;
	
	ll b2=d/2-(c-1)/2;
	ll b8=d/2018-(c-1)/2018;
	ll b9=d/1009-(c-1)/1009;
	
	ll al=b-a+1,bl=d-c+1;
	
	sum=al*b8+bl*a8-a8*b8+(a9-a8)*(b2-b8)+(b9-b8)*(a2-a8);
	
	cout<<sum<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值