无情铁首,开最后一题的调试时间来不及只能说是实力不足…
time limit per test : 4 seconds
memory limit per test : 512 megabytes
inputstandard input
outputstandard output
Tang Keke is good at math. She knows how to simplify fractions very well. Even greater, she invented a simplifying method by herself!
The method is to choose some digits which appear in both the top and the bottom and erase them on both sides while keeping the fraction value unchanged. The digits are the same, so they can reduce each other. Sounds very logical, right?
The method may produce multiple simplified results and the one with the least top number is called the most simplified form. Keke prepared some fractions and is going to test if you can get the most simplified form.
Note that the chosen digits form a multiset, you can see the examples for more details.
Input
The first line contains an integer n (1 ≤ n ≤ 10), denoting the number of fractions.
Each of the next n lines contains two integer p,q (0 < p,q <2^63), denoting the fraction p/q.
Output
For each fraction, output two integers x,y in one line, indicating the most simplified form of the corresponding fraction is x/y.
Notice: if there are some leading zeros after removal, you can ignore them and output the normal number. For example, if you get 007/123 finally, then you should output “7 123” instead of “007 123”.
input
4
163 326
326 163
1000 1000
2232 162936
output
1 2
2 1
1 1
232 16936
#include
using namespace std;
//必须开__int128 否则在计算分母时1e18*1e18会炸long long
inline __int128 read()
{
__int128 x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(__int128 x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)write(x/10);
putchar(x%10+'0');
}
__int128 qpow(__int128 a,__int128 x)
{
__int128 sum=a,ans=1;
while(x>0)
{
if(x%2==1)ans*=sum;
sum*=sum;
x>>=1;
}
return ans;
}//可预处理10的幂次 这里傻逼了不过影响不大
int n;
int av[11],bv[11];
__int128 a,b,mn;
map<__int128,int> mp;//因 Key类型为__int128故不使用unorded_map
int u[11];
int mx;
__int128 aa,ab,md,ya,yb;
__int128 ck(__int128 x,__int128 n,int d)//返回 x 删右起第 d 个 n
{
int z=0;
__int128 sum=0,sum1=0;
__int128 cd=0;
while(x>0)
{
++cd;
md=x%10;
x/=10;
if(md==n)++z;
if(z<d)
{
sum1=sum1+md*qpow(10,cd-1);
}
if(z==d)break;
}
sum=x*qpow(10,cd-1);
return sum+sum1;
}
int jd(__int128 x)
{
if(x*yb%ya!=0)return 0;//如删后的 a 对应的分母不为整数,既不合法
else
{
__int128 bp=x*yb/ya;
int at[11]={0},ct[11]={0};//ct桶存储删掉的数
queue<int> st;//使用堆保证留下的数的顺序与原数顺序能进行判断
while (!st.empty())st.pop();
__int128 md;
__int128 lya=ya,lyb=yb;
while(x>0)
{
md=x%10;
++at[md];
x/=10;
}
while(lya>0)
{
md=lya%10;
if(at[md]>0)
{
--at[md];
}
else
{
++ct[md];
}
lya/=10;
}
while(bp>0)
{
md=bp%10;
st.push(md);
bp/=10;
}
st.push(-1);//空堆的front()==0会对判断进行干扰 于是在堆尾推个 -1
int f=1,yl=0;//如高位的数删除后前导0会自动删除 故记忆前导零的情况
while(lyb>0)
{
md=lyb%10;
if(st.front()==md)
{
if(yl==1)return 0;//如前导零存在但前数未被删除既不合法
st.pop();
}
else if(ct[md]>0)--ct[md];
else if(md==0)
{
yl=1;//记忆前导零情况
}
else return 0;
lyb/=10;
}
if(st.front()!=-1)f=0;//堆若为非空既不合法
if(f==1)
{
for(int i=0;i<=9;++i)
{
if(ct[i]!=0)//若删除的数未全部用上亦不合法
{
f=0;
break;
}
}
}
return f;
}
}
void dfs(__int128 a,int s)
{
if(mp[a]!=0)return;
mp[a]=1;//避免处理重复数字
if(jd(a)==1)//判断处理出来的 a 对应的分母是否合法
{
if(a<aa)//为符合题意中留下 分子最小 的解
{
aa=a;
ab=a*yb/ya;
}
}
if(s==mn-1)return;//个位数的情况不能再继续处理
for(int i=0;i<=9;++i)//枚举删哪个数
{
if(av[i]==0||bv[i]==0)continue;
else if(u[i]<av[i]&&u[i]<bv[i])
{
int ag=av[i]-u[i];
for(int j=1;j<=ag;++j)
{
++u[i];
dfs(ck(a,i,j),s+1);//枚举删右起第 j 个 i
--u[i];
}
}
}
return;
}
int main()
{
scanf("%d",&n);
while(n--)
{
mp.clear();
mx=0;
a=read();
b=read();
for(int i=0;i<=9;++i)
{
av[i]=0;
bv[i]=0;
u[i]=0;
}
__int128 ac=0,bc=0;
__int128 awl=0,bwl=0,na=a,nb=b;
while(na>0)
{
md=na%10;
na/=10;
if(md!=0)break;
++awl;
}
while(nb>0)
{
md=nb%10;
nb/=10;
if(md!=0)break;
++bwl;
}
mn=min(awl,bwl);
__int128 cl=qpow(10,mn);
a/=cl;
b/=cl;//处理两数尾端共同数量的 0
na=a;
nb=b;
while(na>0)
{
++ac;
na/=10;
}
while(nb>0)
{
++bc;
nb/=10;
}
if(ac<=1||bc<=1)
{
write(a);
printf(" ");
write(b);
puts("");
continue;
}
mn=min(ac,bc);//得到两数长度的最小值
__int128 la=a,lb=b;
aa=a;
ab=b;
while(la>0)
{
md=la%10;
la/=10;
++av[md];
}
while(lb>0)
{
md=lb%10;
lb/=10;
++bv[md];
}//统计 a,b 两数中各数字出现的次数
ya=a;
yb=b;
for(int i=0;i<=9;++i)
{
if(av[i]!=0&&bv[i]!=0)
{
dfs(a,0);
break;
}
}
write(aa);
printf(" ");
write(ab);
puts("");
}
return 0;
}