Photo 题解
Photo 题解
#5142 YAOI Round #17 (Div.2) B. Photo
题意分析
读入分数序列,求指定区间内的和。
由于是查询区间和,很容易想到前缀和,只需要再套上一个分数的计算即可。
分数计算
加减
以 \(\dfrac{a}{b} + \dfrac{c}{d}\) 为例讲解。
先将两个分数通分(显而易见公分母为 \(b \times d\)),得到 \(\dfrac{a \times d}{b \times d} + \dfrac{c \times b}{d \times b}\)。
因此得到 \(\dfrac{a}{b} + \dfrac{c}{d} = \dfrac{a \times d + b \times c}{b \times d}\)。
减法同理,\(\dfrac{a}{b} - \dfrac{c}{d} = \dfrac{a}{b} + \dfrac{-c}{d} = \dfrac{a \times d - b \times c}{b \times d}\)。
约分
提示中有提到 __gcd(a,b) 可以返回 a 和 b 的最小公因数,而经过简单思考可以明白将分数的分子分母同时除以它们的最小公因数后,这个分数最简,便解决了约分的问题。
细节
分母为 0
若没有第 21 行先将分母赋值为 1,会全部 RE。
读入时未化简
如果读入时未化简会导致相加时溢出,变成负数,导致 WA。
特意卡的,关键在会变 WA 而非 RE。
模错模数
注意是 \(998442553\) 而不是 \(998244353\)!
正解
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,t;
int p[10005],q[10005];//p 记录分子,q 记录分母
void pls(int p1,int q1,int p2,int q2,int &ans1,int &ans2) {
//p1 第一个分子,q1 第一个分母,p2 和 q2 表示第二个分子和分母
//ans1 答案分子,ans2 答案分母
int p=p1*q2+q1*p2,q=q1*q2;//p 答案分子,q 答案分母
int tmp=__gcd(p,q);//最小公因数
ans1=p/tmp,ans2=q/tmp;//约分至最简
}//加
//减同理,传入第二个分子时加上负号即可
const int m=998442553;//模数
signed main() {
scanf("%lld",&n);
p[0]=0,q[0]=1;//分母不能为 0
for(int i=1; i<=n; i++) {
int a,b;
scanf("%lld%lld",&a,&b);
int g=__gcd(a,b);//读入时先化简
pls(p[i-1],q[i-1],a/g,b/g,p[i],q[i]);//计算前缀和
}
scanf("%lld",&t);
for(int i=1; i<=t; i++) {
int l,r;
scanf("%lld%lld",&l,&r);
int t1,t2;
pls(p[r],q[r],-p[l-1],q[l-1],t1,t2);//计算区间和
//注意第二个分子前的负号
printf("%lld %lld\n",t1%m,t2%m);//最后取模输出
}
return 0;
}
后记
标程经过读入优化,跑样例 10 只要 \(0.05s\) 左右,因此这题时限是给了大约 \(10\) 倍 std,真是良心出题人。

浙公网安备 33010602011771号