数学题(找规律)

题目链接:https://www.nowcoder.com/acm/contest/89/B
来源:牛客网

题目描述

There is a formula:

gcd(a, b) is the greatest common divisor of a and b.

Give you three integers L, R and K. Please calculate the value of the following formula:


输入描述:

 
 
The first line contains an integer T, where T is the number of test cases. T test cases follow. 
For each test case, the only line contains three integers L, R and K.

• 1 ≤ T ≤ 20.

• 1≤ L ≤ R ≤10 18
• 1 ≤ K ≤ 10 5.

输出描述:

For each test case, output one line containing “Case #x: y”, where x is the test case number (starting
from 1) and y is the answer.

题目大意:两个数l和r,和取模的k,在l和r之间(包括r,l)找所有符合要求的数之积;

要求是与k的数字的gcd是1符合要求;

方法没什么,主要是用了gcd和快速幂,不知道的有链接;

快速幂:https://blog.csdn.net/qq_40482358/article/details/79323636

规律就是每k个数为一组,多余的直接求;

举个例子:5-25,k=6;

6符合要求的是5;

5-25之间21个数,三个余数;

一:5,6,7,8,9,10;            //8,9,10,11,12,13;

二:11,12,13,14,15,16;    //14,15,16,17,18,19;

三:17,18,19,20,21,22;    //20,21,22,23,24,25;

余:23,24,25;                        //5,6,7;

符合要求的数是:5,7,11,13,17,19,23,25;

都一样的分法,只是习惯不同而已;

计算一下会发现每组数据都一样:5*7%6=5;11*13%6=5;17*19%6=5;23*25%6=5;

和6的除因子之积对6取模的结果相等;

为什么呢?

因为凡是6的因数就肯定是不符合条件数子的因数,所以就排除了这些数了,剩下的这些数的乘积取模就必定是其余的数的乘积取模;

推导致一般规律就是下面的代码了:

ac:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h> 

//#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

#define ll long long
#define da    0x3f3f3f3f
#define xiao -0x3f3f3f3f
#define clean(a,b) memset(a,b,sizeof(a))// 雷打不动的头文件

//注意数据范围 
ll gcd(ll x,ll y)
{
    return y?gcd(y,x%y):x;		//gcd 
}

ll quick(ll x,ll n,ll k)		//快速幂 
{
	ll ji=1;
	while(n)
	{
		if(n&1)
			ji=ji*x;
		x=(x*x)%k;
		n=n>>1;
	}
	return ji;
}

int main()
{
	int t,kind=1;
	cin>>t;
	while(t--)
	{
		ll l,r,k;
		cin>>l>>r>>k;
		ll repeat,remain;
		repeat=(r-l+1)/k;		//共repeat个重复单元 
		remain=(r-l+1)%k;		//共remain个多余单元 
		ll i,j;
		ll ji=1;				//乘积初始话为一 
		for(i=2;i<k;++i)
		{
			if(gcd(k,i)==1)		//k的所有因数找出来相乘 
				ji=ji*i%k;		//避免爆ll,对k取余 
		}
		ji=quick(ji,repeat,k);	//共repeat个重复单元,运算repeat次 
		for(i=l;i<l+remain;++i)	//对于多出来的部分符合要求的乘上去,不符合的相当于乘一 
		{
			if(gcd(k,i)==1)
				ji=(i%k)*ji%k;
		}
		cout<<"Case #"<<kind++<<": "<<ji%k<<endl;
	}
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值