CF #582 Div.3 C - Book reading (思维题,简单预处理)

本文介绍了一种高效算法,用于计算从1到n范围内所有m的倍数的个位数字之和,避免了暴力计算的复杂度。通过发现倍数的周期性规律,将问题分解为完整周期和剩余部分的计算,显著提高了计算效率。

题目要求输出 从 1 ~ n 中 所有 m 的倍数的个位数之和。

n很大, 暴力肯定不行,而但凡是数,都有一定的规律性,

一个数的倍数又有什么规律呢?  

以 3 为例,

1倍就是一个3,  两倍就是 两个3相加, 三倍就是 三个 3 相加,直到十倍, 以十倍为一个循环,十一倍时又是一个新的循环的开始,

3 6 9 12 15 18 21 24 27 30      |    33 36 39 42 45 48 51 54 57 60 .....

很容易看出每相隔 30  ,3的所有倍数的个位数之和都是一个定值, 3 + 6 + 9 + 2 ....+...+ 7

所以我们只需要求出 n 中有几个30 然后 在乘以     3 + 6 + 9 + 2 ....+...+ 7,就先算出了1 ~ (n / 30)* 30  的答案。

最后, 加上 n - (n/30) * 30 中 3 的倍数的个位数之和就OK了。

代码:

#include <iostream>
#include <string>
using namespace std;
#define ll unsigned long long
ll f(ll m,ll &q){  
	ll sum = 0;
	for(ll i = m,j = 2; i%10!=0;j++ ){  // 将 m 分别与 1 ~ 9 相乘, 记录 m ~ m*9 中不同个位的和. 
		sum+=i%10;
		i = m * j;
		q = i;
	}
	return sum;
}
int main(){
	int T;
	cin>>T;
	while(T--){
		ll m;ll n;
		cin>>n;	
		cin>>m;
                // 剪枝不加这一步会超时,当m为10的倍数, m的所有倍数的个位都是0,直接输出0 
		if(m % 10 == 0|| n < m) {cout<<"0"<<endl; continue;}   
		if(n == m) {cout<<n%10<<endl; continue;} //当n==m 直接输出n%10 
		
		ll sum = 0, q, p;	 // q保存当m的倍数的个位数再次重复出现时的第一个值。则 每 一个 q , 都含有
		
		p = f(m,q);  // p保存从m~q的所有个位不同的倍数的数量。 
		ll y = n / q; // 则 n / q 是  n 中 一共有几个 q, n不能为10的倍数,否则此处会除以0!  
		sum = y * p;  //每隔 q,m的不同个位的倍数之和都为p  所以 sum = y * p; 
		n = n - y *q; //然后算剩下的数 
	
		if(n){
			for(ll i = m,j = 2; i<=n;j++){
				sum+=i%10;
				i = m*j;
			}	
		}	
		cout<<sum<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值