当前位置: 代码迷 >> 综合 >> 计蒜客----F. Fractions
  详细解决方案

计蒜客----F. Fractions

热度:28   发布时间:2024-02-11 20:35:26.0

我喜欢给自己压力,必须得定一个很高的目标,逼自己朝着这个目标前进,不管会不会实现,都是一个动力。                                      ----喻言

题目:

题意:

凑几个分数的和为 (n-1)/n,要求分母(也就是题目中的b)是n的因数

分析:

题目中的式子可以写成:n-1=a1*q1+a2*q2+……+am*qm;可以得出所有不和n互质的数,都可以写成至少一个质因数的倍数。也就是上面的qi,我们又知道一个较大的质数肯定可以用两个较小的质数的倍数叠加来表示出来,那上面的式子通过合并就可以写成n-1=ax+by的形式,我们就考虑用n的较小的两个质因数凑答案就可以。下面就是求解n-1=ax+by方程了。

裴蜀定理:对于给定的正整数a,b,方程a*x+b*y=c有解的充要条件为c是gcd(a,b)的整数倍。也就是对于ax+by=c,若c%gcd(a,b)==0,则有且有无数组解(求出一组解即可),否则无解。

求出的x,y可正可负,显然我们这里要求正整数解,所以我们接下来的一个问题就是要把x,y配成正整数。如果两个都正了,更好,直接输出答案就可以;否则肯定是一个正,一个负。不妨令x是负的那个,然后我们会发现,如果x,y是一个满足条件的解,那么x+b,y?a也是一个满足条件的解(代入一下会发现两个ab抵消了)。那么,我们只需要将y不断的?a,x不断的+b,就可以把x,y配成正的。这时可能想到,要是配不成咋办?事实证明没有这样的情况。。。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#include<climits>//INT_MAX
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int mod=1e9+7;
ll gcd(ll a,ll b){//求最大公因数 return b?gcd(b,a%b):a;
}
ll exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得求解x,y if(b==0){x=1;y=0;return a;}ll g=exgcd(b,a%b,x,y);ll tmp=x;x=y;y=tmp-a/b*y;return g;
}
int main(){ll n,fg=0;scanf("%lld",&n);for(ll i=2;i*i<=n;i++){if(n%i==0){ll a=i;ll b=n/i;ll g=gcd(a,b);if(a!=b&&(n-1)%g==0){//有解 ll x,y;ll tmp=exgcd(a,b,x,y);//这里求解来出的x,y是方程ax+by=g的解//可转换成ax(n-1)/g+by(n-1)/g=n-1 ll xx=(n-1)*x/g;ll yy=(n-1)*y/g;//求解出来的x,y可能是正数也可能是负数,相应的xx,yy亦是如此 //可以肯定的是结合原式可以知道xy其中一个若为负,则另一个必定为正,要不结果不可能为正数,配数方法见文档说明 while(xx<0){//xx为负 xx+=b/g;yy-=a/g;}while(yy<0){//yy为负 xx-=b/g;yy+=a/g;}
//                if(xx<0&&yy<0)
//                    continue;printf("YES\n2\n%lld %lld\n%lld %lld\n",yy,a,xx,b);fg=1;break;}}}if(!fg)printf("NO\n");return 0;
}