(AC)架子鼓
题目描述
小K正在学习架子鼓。因为他刚刚开始,所以还只会军鼓和底鼓。他面前有两段乐谱,分别表示军鼓和底鼓的节奏,他需要同时演奏这两段节奏。每段乐谱有若干个音符,每个音符有一个时长,用一个分数
p/q来表示,其中p,q是互质的正整数,并且q∈{1,2,3,4,6,8,16}。对于每个音符,小K需要在这个音符对应的时长开始的时刻,击打对应的乐器。特殊地,在时刻0,小K一定同时击打军鼓和底鼓的第一个音符。请问小K有多少次同时击打军鼓和底鼓。输入
多组测试数据。第一行表示测试组数T,满足 1≤T≤100。
之后每组数据,第一行是两个整数n1,n2 ,分别表示军鼓和底鼓的乐谱的音符数量。
之后n1 行,每行两个整数pi,qi , 代表军鼓的第i个音符的时长为pi/qi。
之后n2 行,每行两个整数pj,qj ,代表底鼓的第j个音符的时长为pj/qj。
保证1≤n1,n2≤104,并且对于所有的i和j,满足qi,qj∈{1,2,3,4,6,8,16},1≤pi,pj≤102,以及pi,qi 互质、pj,qj 互质。输出
对于每组测试数据,输出一个整数,表示小K同时击打军鼓和底鼓的次数。
样例输入 Copy
1 2 4 1 2 1 2 1 4 1 4 1 4 1 4样例输出 Copy
2提示
军鼓击打的时刻有{0,1/2},底鼓击打的时刻有{0, 1/4,1/2,3/4},其中重合的击打时刻有2次。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
int t,n1,n2;
ll gcd(ll a,ll b){while(b!=0){ll temp=b;b=a%b;a=temp;}return a;
}
P jam(P a,P b){ll p=a.first*b.second+b.first*a.second;ll q=a.second*b.second;ll g=gcd(p,q);return {p/g,q/g};
}
int main(){scanf("%d",&t);while(t--){scanf("%d%d",&n1,&n2);P a,b,x{0,1},y{0,1};set<P>book;int ans=0;while(n1--){book.insert(x);scanf("%lld%lld",&a.first,&a.second);x=jam(x,a);}while(n2--){if(book.find(y)!=book.end())ans++;scanf("%lld%lld",&b.first,&b.second);y=jam(y,b);}printf("%d\n",ans);}return 0;
}