【杂言】:
我是真的不想写了,但是,我挂了,挂的很彻底,30分钟找思路,1个小时修了三遍码,全挂了,被迫看题解,我真是醉了,一到分母,则为坟墓,(可能上天不想让我充当别人的分母吧) , (UVA)的题,真的太狗了,好倒是挺好,这个输出就 ,,,算了,不吐槽了,但是我看了题解,看了题解就要写解题报告,这是习惯。
【题目描述】:
给定一个分数 (dfrac{a}{b}),然后给定 (k) 个数 (q_i)。
要求把 (dfrac{a}{b}) 分为几个不同的分子为 (1) 的最简分数,要求分成的分数的分母中不能出现 (q_i)。
本题有 (t) 组数据, (t le 100)。
其他数据范围: (2 le a < b le 876), (0 le k le 5), (gcd(a,b)=1), (2 le q_i le 1000)。
【思路分析】:
想想,对于分数的分解问题,有没有好的数学方法去解决,因为往往数学能够解决的,信息中也就太简单了, 显然, 数学中也没有什么好方法,看到了 数据总共也不是很大,那么也就是只能搜索了,
对于搜索,朴素的搜索我写挂了(@ο@) ~, 悲伤的事情,想起就是难过的经历。
至于这道题的朴素写法, 那就是枚举有关(这里姑且说为有关)的分母,然后对于每一个分母相加起来,看看是否是可以与给定的数值相等, 如果可以,那就进行比较,同时确保这一个分母可以用和比较是否用这个分母是最优的 。 --- 这就是最朴素的搜索思路了。
然后便是有关分母的枚举上界和下界问题 , 总不能枚举到 (10^9)的枚举吧
有关其下界问题: 其下界也就是上一个用到的分母加 1 和 $frac{b imes y}{ b imes x - a imes y} $ 的最大值;
解释一下 :
上一次用到的分母加 1 , 不必说明了 。
$frac{b imes y}{ b imes x - a imes y} $的推导,
我们设其上一个字母为 (kkk)
也就是说 (frac{a}{b}) + (frac{1}{kkk}) (leq frac{x}{y}) , 然后化简,不会可以找小学老师了(逃) ,
有关其上界问题 :
设的变量 ,$d=现在迭代的次数 dep是现在迭代到的数 $ ,
那么(max = frac{frac{x}{y} - frac{a}{b} }{d - dep}) ,很显然 , 为了我们的精度, 我们可以转化为( imes)的形式;
即为 : (b imes y imes (d - dep) + a imes max imes >= x imes b imes max) ,相当于一个终止条件嘛 , 也没必要去在意值。(值是你枚举的,管他干嘛?)
【注意一下】:
- 很明显,我们选用 (set)去判别有没有这个值是更优的 (以(log_2 n)的)
- 更为明显, 分数必须要约分 , 不约分等于白做
- 他的输入输出是很毒瘤的 , 不能就随便输出的
- 不要忘记(set)迭代器转化为(int)类型 , 不然一直(CE) 。
【Code】:
暂且先放下代码,日后再补上,毕竟要去考试了呀~
(TM)考试考炸了
#include <iostream>
#include <cstdio>
#include <cstring>
//#include <algorithm> //打死我也没想到,algorithm我竟然定义了其中的关键词,为了解决这个问题,我决定,不用他,哈哈
#include <cmath>
#include <cstdlib>
#include <queue>
#include <set>
#define inf 0x3f
#define int long long
#define QwQ printf("运行过了") ;
using namespace std ;
const int maxn = 1e5 ;
inline int read()
{
int x = 0 , f = 1 ; char ch = getchar() ;
while(!isdigit(ch)){ if(ch =='-') f = - 1 ; ch = getchar() ; }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar() ; }
return x * f ;
}
int gcd(int x,int y)
{
return !y?x:gcd(y,x%y);
}
int lcm(int x , int y)
{
return x / gcd(x,y) * y;
}
//分数相减通分公式(a*x-b)/b*x
int x , y , k , dep , tot = 0;
bool vis[maxn] ;
set<int> s ;
vector<int> now ,ans ;
void check()
{
if(ans.empty() ||ans.size() > now.size())
{
ans = now ;
return ;
}
if(now.size() > ans.size() ) return ;
for(int i = (int)now.size() - 1 ; i >= 0 ; i--)
{
if(now[i]<ans[i])
{
ans = now ;
return ;
}
else if(now[i] > ans[i] )
{
return ;
}
}
return ;
}
void prepare() // 多组数据每次都进行初始化
{
now.clear() ;
ans.clear() ;
memset(vis , false ,sizeof(vis)) ;
s.clear() ;
return ;
}
void search(int d , int last , int a , int b)
{
if(a * y > b * x)
{
return ;
}
if(d >= dep)
{
if( a * y == b * x) check() ;
return ;
}
int p = gcd(a, b) ;
a /= p , b /= p ;
int head = max(last , y * b / (x * b - y *a) ) ;
for(int i = head ; b * y * (dep - d ) + a * i * y >= x * b * i ; i++)
{
if(s.count(i)) continue ;
now.push_back(i) ;
search(d + 1 , i + 1 , a * i + b , b * i) ;
now.pop_back() ;
}
return ;
}
void work()
{
prepare() ;
x = read() , y = read() , k = read() ;
while(k--)
{
int m = read() ;
s.insert(m) ;
}
int gcd_ = gcd( x , y ) ;
x /= gcd_ , y /= gcd_ ;
for(dep = 1 ; ans.empty() ; dep ++)
{
search(0 , 2 , 0 , 1) ;
}
printf("Case %lld: %lld/%lld=" , ++tot , x , y ) ;
printf("1/%lld", ans[0]) ;
for(int i = 1 ; i < (int)ans.size() ; i++)
{
printf("+1/%lld" , ans[i]) ;
}
printf("
") ;
return ;
}
signed main()
{
int T = read() ;
while(T--)
{
work() ;
}
return 0;
}