Fractions 猜公式+扩展gcd
程序员文章站
2022-06-08 12:28:41
...
Fractions
题意:
给一个n,构建一个序列,使得满足这3个条件
原题:
题目来源 ICPC Northeastern European Regional Contest 2018
(链接不好找,计蒜客里复现赛里的)
解题分析:
-
猜公式:经过实验观察,对于任意m,只要m不是质数,b= , 那么 ax+by=n-1 就能成立。
-
证明公式,
假设
那么也就是
若gcd(a,)=1,则必定存在 , n-1是1的倍数,则若gcd(a,)$\neq$1,
假设 成立
那么
$\therefore (n-1)·a %gcd(a^2,n) = (n-1)%f \neq 0 $
综上所述,可以证得 只有当 gcd(a,)=1时,必然能使得 有整数解。
-
证明有必定存在x和y都是正数使得 成立 ,记 b= ,是(2)下的x的最小正整数解
而既然必定存在,那么只要找到 的最小正整数解就可以,因为在相加情况下存在,一个小了,另一个不是更有可能是正数么。
- 求 的最小正整数解,其中 a>=0, ,符合 扩展欧几里德的使用条件。
代码
算法步骤
- 对n分解,分解成的形式(p是素数), 取a=
- 令 带入exgcd求解,得到x和y之后,做最小正整数处理
#include "bits/stdc++.h"
using namespace std;
#define ll long long
int exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){x=1;y=0;return a;}
int r=exgcd(b,a%b,x,y);
int tem=x;
x=y;
y=tem-a/b*y;
return r;
}
int main()
{
int n;
scanf("%d",&n);
int fac=0,nn=n,size=0;
for(int i=2;i*i<=nn;++i)
{
if(nn%i==0) {
int tem = 1;
while (nn % i == 0) {
nn /= i;
tem *= i;
}
if (!fac)fac = tem; //只要找到一个就行
size++;
}
}
if(nn>1)size++;
if(size<=1)puts("NO");
else {
puts("YES");
puts("2");
int a=fac,b=n/fac,c=n-1; //此处开始套公式,ax+by=c ,最小正整数解x=x*c%( b/gcd(a,b))
ll x,y; // 一定要用long long,不然在使用exgcd的时候会wa
int gcd=exgcd(a,b,x,y);
int mod=b/gcd;
x=(x*c/gcd %mod+mod)%mod; //防止负数
y=(c-a*x)/b;
printf("%d %d\n%d %d\n",x,n/a,y,n/b);
}
return 0;
}
下一篇: 企业网站制作最终章:网站备案
推荐阅读