除法表达式
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
给出一个这样的除法表达式:X1/X2/X3/···/Xk,其中Xi是正整数。除法表达式应当按照从左到右的顺序求和,例如表达式1/2/1/2的值为1/4。但是可以在表达式中嵌入括号以改变计算顺序,例如表达式(1/2)/(1/2)的值为1.判断能否通过加括号使表达式的值为整数??

输入
首先输入一个N,表示有N组测试数据,
每组数据输入占一行,为一个除法表达式,
输入保证合法。
使表达式的值为整数。k<=10000,Xi<=100000000.
输出
输出YES或NO
样例输入
1
1/2/1/2
样例输出
YES

定理一:
唯一分解定理:任何一个数都能写成素数相乘的形式:
X=p1^a1 *p2^a2 *p3^a3 *p4^a4…
定理二:
gcd(a,b)=gcd(b,a%b),
gcd(a,0)=a
用这两个定理可以轻松构造出辗转相除法
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);}
定理三:
gcd(a,b)*lcm(a,b)=a * b(这个我还没明白怎么证明的,改天找老师问一下)
lcm(a,b)=a * b / gcd(a,b) //a * b可能会溢出
lcm(a,b)=(a/gcd(a,b)) * b//防止溢出
辗转相除法的时间复杂度是logn
辗转相除法也称为欧几里得算法

这题判断它能不能整除,我们可以先将表达式改变形式为(x1x3x4*…*xn)/x2
然后只需要判断最后x2是否等于1,分母为1才整除,让后让x2每次和xi约分,约分只需要求gcd (x2,xi)就行了。

代码:(未ac,找不到平台)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int a[maxn];
int cnt;
bool __(){
	int g=__gcd(a[0],a[1]);
	a[1]/=g;
	for(int i=2;i<cnt;i++){
		if(a[1]==1)return true;
		a[1]/=__gcd(a[i],a[1]);
	}
	if(a[1]==1)return true;
	return false;
}
int main(){
	int n;
	scanf("%d",&n);
	while(n--){
		memset(a,0,sizeof(a));
		char str[maxn*2];
		scanf("%s",str);
		str[strlen(str)]='/';
		int ans=0;cnt=0;
		for(int i=0;i<strlen(str);i++){
			if(str[i]=='/'){
				a[cnt++]=ans;
				ans=0;
			}else{
				ans=ans*10+(str[i]-48);
			}
		}
		int p=__();
		if(p){
			cout<<"YES"<<endl; 
		}else{
			cout<<"NO"<<endl;
		}
	}
	
}