陈太阳与取模(数学思维题)

题目大意

陈太阳打了一个响指,这世上的数字便都减少了一半。
对于所有在 [ L , R ] [L,R] [L,R]中的正整数,陈太阳将他们都变成了除以A的余数。现在陈太阳想知道有多少个正整数X,满足对于任意正整数 i ∈ [ L , R ] i∈[L,R] i[L,R],都有
i m o d X ≡ ( i m o d A ) m o d X imodX≡(i modA)modX imodX(imodA)modX
给定A,L,R,请你计算有多少个满足条件的X。

输入格式
本题有多组测试。
第一行一个整数T表示测试组数,接下来每行一个测试点,三个正整数 L , R , A L,R,A L,R,A
输出格式
对于每个测试点,如果有无数个满足条件的X,输出"-1"。否则输出一个数,表示有多少个X满足条件。

样例1
i n p u t input input
4
1 1 1
3 5 2
1 10 10
1 1 2
o u t p u t output output
1
2
4
-1

样例2
i n p u t input input

11
64 92 77
12 83 35
59 66 38
14 46 92
25 68 62
11 29 81
9 46 28
34 82 34
33 60 18
17 62 59
529 535 66

o u t p u t output output

4
4
4
-1
4
-1
6
4
6
2
20

数据规模与约定
20%的数据保证1≤L,R,A≤100
40%的数据保证1≤L,R,A≤ 1 0 5 10^5 105
另外20%的数据保证A<L
另外20%的数据保证R−L≥A
100%的数据保证T≤100 1≤L,R,A≤ 1 0 12 10^{12} 1012 L≤R
时间限制: 1s
空间限制: 512MB
提示
m o d mod mod 表示模运算。a m o d mod mod b表示a除以b的余数,比如说8 m o d mod mod 3=2。

题解

首先,我们可以知道,当A>R时直接输出-1,此时X∈(R,+∞],X∈ R + R^+ R+
然后由题意可列出
i m o d X = ( i m o d A ) m o d X imodX=(i modA)modX imodX=(imodA)modX
我们令i=A*p+q(0<=q<A)
那么原等式可化简为:
i m o d X = q m o d X imodX=qmodX imodX=qmodX
还可以接着化简:
( A ∗ p + q ) m o d X = q m o d X (A*p+q)modX=qmodX (Ap+q)modX=qmodX
那么最重要的一步就出来了:
A ∗ p ≡ 0 ( m o d X ) A*p≡0(modX) Ap0(modX)
注意,这里的A为定值,而p随i递增的,也就是p是在变化的,
那我们X的取值就要讨论了:
①p不变
此时说明i/r为定值( i ∈ [ L , R ] i∈[L,R] i[L,R])
也就是区间[L,R]全部落入一区间[A*p,A*(p+1))中
而我们要使 A ∗ p ≡ 0 ( m o d X ) A*p≡0(modX) Ap0(modX),显然X为A*p的因数均可.

②p变
那么我们可以知道区间[L,R]至少跨越了一个形如[Ak,A(k+1))的区间
设[L,R]落入区间[Al,A(r+1))(l+1<r)中,那么p∈[l,r]
我们又知道 g c d ( l , l + 1 , l + 2 , . . . , r ) = 1 gcd(l,l+1,l+2,...,r)=1 gcd(l,l+1,l+2,...,r)=1,p对X没有约束条件
于是这里只有A对X有约束条件,那么此时X为A的因数均可
算因数用因数个数定理或者暴力均可,我用的因数个数定理.

代码

#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
LL read(){
    LL f=1,x=0;char s=getchar();   
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}  
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
#define MAXN 200000
#define MAXL 1000000
#define INF 0x3f3f3f3f
#define Mod int(1e9+7)
bool check[MAXL+5];
int tot,prime[80000+5];
void Prime(){
	for(int i=2;i<=MAXL;i++){
		if(!check[i]) prime[++tot]=i;
		for(int j=1;j<=tot&&1ll*i*prime[j]<=MAXL;j++){
			check[i*prime[j]]=1;
			if(i%prime[j]==0) break;
		}
	}
	return ;
}
LL Cnt(int a){
	LL ret=1;
	for(int i=1;i<=tot;i++)
		if(a%prime[i]==0){
			LL tmp=1;
			while(!(a%prime[i])) a/=prime[i],tmp++;
			ret*=tmp;	
		}
	return ret;
}
int main(){
	Prime();
	int T=read();
	while(T--){
		LL ans,l=read(),r=read(),a=read();
		if(a>r){
			puts("-1");
			continue;
		}
		ans=Cnt(l/a!=r/a?a:l/a*a);
		printf("%lld\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值