CF1342C Yet Another Counting Problem 题解
题解索引
- 题目大意
- Solution
- AC code
- 类似题型
代码类型: C++(cpp)
是否吸氧:否
不压行代码长度:29
这篇题解挺长的,慎点。
题目大意
题面: <传送门>
题意:
初始给出
给出
有
术语理解: 小学数学,周期问题和最小公倍数。
Solution
首先排除暴力,单是一组极限数据
Part 1 思路引入
我们先来看这个:
这证明,取模的结果是有一定规律的 突然回到扩欧。
比如:
我们把
我们发现,这些数之间是有一定规律的,相邻两个数的差是
可以得出:
我们把原题的式子拿过来嗷:
我们先处理一个:
我们在计算是
而我们之前说过,取模的结果是有一定规律的。所以,我们可以得出这玩意:
我们再把另一个式子也进行这样处理(这里不放了,与这个一样,就是把模数换了)。于是,这就成了一个周期问题。
Part 2 周期问题
Q:这啥啊,跟这题有关联吗?
A:没关联我能放上来嘛? 好像真能
我们再把刚刚求得的公式搬过来:
我们发现,相邻的两个数之间的不同是
如果抛去取模不说,相邻两个数之间的差异确实是
如果我们处理第二组中的数时,是否可以看出处理第一组中的数呢?答案是可以的。
举个取模的例子,比如
可以轻松得出一个周期是:
那我们求任何一个周期中的某数时,是不是也可以从这个周期里找呢?比如我们求
这个问题不就轻松解决了?
Part 3 整理思路
之前我们说过了,一个周期就是
看到这种题很容易想到前缀和吧?既省时又省力。
那怎么求最小公倍数呢?
这里
注意!有一个坑点!最后我们在处理每对
因为
AC code
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAX=40009;
typedef long long ll;
int t,q;
ll s[MAX];
ll a,b;
int gcd(int a,int b){//获取最大公因数
return b==0?a:gcd(b,a%b);
}int main(){
scanf("%d",&t);
while(t--){
scanf("%lld %lld %d",&a,&b,&q);
ll _lcmab=a*b/gcd(a,b);//前面说过这个方法
for(int i=1;i<=_lcmab;i++){//注意是处理到lcm(a,b)
s[i]=s[i-1];//首先赋值过来
if(i%a%b!=i%b%a)s[i]++;//如果符合要求就+1
}for(int i=1;i<=q;i++){
ll l,r;
scanf("%lld %lld",&l,&r);
//前面说过,要求出1到l-1和1到r的值后再相减,因为l和r可能不在一个区间中
ll rx=(r/_lcmab)/*周期数*/*s[_lcmab]/*完整周期的计算*/+s[r%_lcmab/*剩下的数量*/]/*剩下的值(构不成周期的)*/;
ll lx=((l-1)/_lcmab/*周期数*/)*s[_lcmab]/*完整周期计算*/+s[(l-1)%_lcmab/*剩下的数量*/]/*剩下的值*/;
printf("%lld ",rx-lx);//输出跟空格即可
}
}
return 0;
}
AC 记录 <传送门>
类似题目
此题考查了最小公倍数和最大公约数的求法,最简单的例题:
P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题