【模板】有理数取余(小白版)

【模板】有理数取余(洛谷P2613)

题目链接

https://www.luogu.com.cn/problem/P2613

解题思路

不知道你是如何找到这个题解的,或者直接百度的,或者在我的其他题解里链接过来的
有理数取余这是一个知识点,也可能配合别的算法出,而让你根据有理数取余的知识输出结果(我猜的~)

言归正传
首先看题目的读入,乍一看好像很简单,cin就行啊。但是看看数据你会发现, 0≤a≤10^ 10001, 0≤ b ≤10^ 10001,这数可不是一般的大啊。因此,我们就要上点新知识了!
快读函数,对于本题来说,并没有什么类型能存下数a数b,所以只能用快读。(也可能有我不知道……)

快读函数

inline int read(){
 	int x=0,f=1;
 	char ch;
 	ch=getchar();
 	while(ch<'0'||ch>'9'){
  		if(ch=='-') f=-1;
  		ch=getchar();
 	}
 	while(ch>='0'&&ch<='9'){
  		x=(x<<3)+(x<<1)+(ch^48);//等价于x=x*10+ch-'0';
		//留个空,下面会说的
  		ch=getchar();
 	}
 	return x*f;
}

讲解一下,
1.inline 内联函数,可以理解为宏定义,比如define ll long long,在编译预处理的时候,编译器会把代码里的ll都换成long long。同理,inline和define一样的效果,只不过inline后面是函数,inline int power (){},在编译预处理的时候,代码中有power函数的地方全部被替换成整个函数,对应参数传入。值得注意的是,因为发生的是宏替换,所以在循环中调用内联函数的时候,会出现代码过长的情况,因为每一次循环调用都会把整个函数的代码展开于你的代码中,即调用几次,你的代码里就出现了多少次整个内联函数代码,这会严重消耗你的内存(准确的说,或许是程序代码区?),所以循环中尽量不要使用内联函数
开始分析快读函数代码了,
2.先看返回值吧。返回的是xf,x表示读入的绝对值,f是符号,xf就是读入的数,返回的也就是读入的数了。
快读函数的读入,都是读入的字符,因为字符读入比数字读入用时少,所以把大数的每一位当成字符读入。
两个while循环,第一个while循环的目的是滤去数字前多余的空格等符号,如果符号为负号,那么我就标记一下f=-1,用于最后的return;第二个while循环读入数字字符,上面代码中的两种形式都可以,表达的含义也是相同的。(x<<3)+(x<<1)的含义是x222+x2=x*10,与注释代码对应。ch^48实现的就是ch-'0’的操作,与注释代码对应。后面的比较好理解,十进制数乘个10,加上个个位的数,前者是后者的二进制实现,所以前者的速度会比后者快点。
3.当第二个循环结束的时候,就是再一次读取到非数字字符的时候,此时代表数字读入结束。
4.注意每个循环中都要进行读取字符操作,这样才能循环起来。

对应到本题来,还是会有问题啊,那return还是没法return这么大的数啊。其实,我们可以在我所留的空白位置加一句x=x%mod;就能实现数的缩小,还不会影响最终要求的结果。具体为什么不会影响,这与取余的运算规则有关,我实在不想细写一遍了,可以看 D题里讲解的知识点(挺重要的)

对于本题,比较特殊,我们要讨论一下无解的情况:(这个题比较全面的包括了分数取余的不同情况)
1.b是mod的倍数:若a也是mod的倍数,那么就存在b*x%mod=a%mod,两边恒等于0,所以x可以是任意整数(无穷解);若a不是mod的倍数,那么等式左边恒等于0,等式右边恒不等于0,所以不存在x使得左右相等。
2.b不是mod的倍数:因为mod是质数,所以mod与b互质,这就满足了费马小定理的前提,所以根据费马小定理变形得必存在x使上述式子成立,即有解。
因此,当且仅当b不是mod的倍数时有解
所以,如果b是mod的倍数,直接输出Angry!就行了。当b不是mod的倍数的时候,再进行计算即可。

还有新知识快速幂,不过到此为止,这个题和上面链接里的D题已经是很类似了,所以我就不多讲了,知识点都可以很详细的在上述链接里看到。(如果你是从那个链接里来的,那你就被我套娃了,hhh)

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=19260817;
inline int read(){
 	int x=0,f=1;
 	char ch;
 	ch=getchar();
 	while(ch<'0'||ch>'9'){
  		if(ch=='-') f=-1;
  		ch=getchar();
 	}
 	while(ch>='0'&&ch<='9'){
  		x=x*10+ch-'0';
  		x%=mod;
  		ch=getchar();
 	}
 	return x*f;
}
ll ksm(ll x,ll t){
 	ll ans=1;
 	while(t>0){
  		if(t&1LL) ans=ans*x%mod;
  		x=x*x%mod;
  		t>>=1;
 	}
 	return ans;
}
int main(){
 	int a,b;
 	a=read();
 	b=read();
 	if(b==0) {cout<<"Angry!"<<endl;return 0;}
 	cout<<a*ksm(b,mod-2)%mod<<endl;
} 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值