X问题 HDU - 1573& Strange Way to Express Integers POJ - 2891
X问题 HDU - 1573& Strange Way to Express Integers POJ - 2891
1. 题意
- 一个数模 mi 等于 ai,第一个问题是求最小的,第二个问题是求x<=n有多少个
2. 分析
合并两个模数
假设
$ y= a_1 (mod \ m_1)$
$ y =a_2 (mod \ m_2)$
令
$ x \equiv a_1 + t_1m_1; (1)$
$ x \equiv a_2 + t_2m_2; ( 2) $
两式相减得 $ t_1*m_1- t_2 *m_2 = a_1 - a_2(3)$
利用欧几里得扩展求出 t1带入(1) 求出一个特解 x
y=x(mod lcm(m1,m2))
证明 x与y同余于 lcm(m1,m2)
m1∣x−y
m2∣x−y
所以 lcm(m1,m2)∣x−y,所以x和y关于 lcm(m1,m2) 同余
3.参考代码
X问题 HDU - 1573
const int maxn = 100;
int aa[maxn];
int bb[maxn];
int N,M;
int ex_gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x = 1;
y = 0;
return a;
}
LL c = ex_gcd(b,a%b,y,x);
y -= a/b*x;
return c;
}
int main(void)
{
int T;
cin>>T;
while(T--)
{
cin>>N>>M;
int A,B;
for(int i = 0; i < M; ++i)
cin>>aa[i];
for(int i = 0;i < M; ++i)
cin>>bb[i];
A = aa[0];
B = bb[0];
bool F = true;
for(int i = 1; i < M; ++i)
{
int x,y;
int d = ex_gcd(A,aa[i],x,y);
int c = bb[i] - B;
if(c%d!=0)
{
F = false;
break;
}
c /= d;
x *= c;
aa[i] /= d;
x = (x%aa[i]+aa[i])%aa[i];
B = B + x * A;
A = A*aa[i];
B = (B%A+A)%A;
}
if(!F)
cout<<0<<endl;
else
{
if(B==0)
cout<<N/A<<endl;
else
cout<< N/A+((N-N/A*A)>=B?1:0)<<endl;
}
}
}
Strange Way to Express Integers POJ - 2891
using namespace std;
long long exgcd(long long m,long long n,long long &x,long long &y)
{
long long x1,y1,x0,y0;
x0=1; y0=0;
x1=0; y1=1;
x=0; y=1;
long long r=m%n;
long long q=(m-r)/n;
while(r)
{
x=x0-q*x1; y=y0-q*y1;
x0=x1; y0=y1;
x1=x; y1=y;
m=n; n=r; r=m%n;
q=(m-r)/n;
}
return n;
}
int main()
{
int n;
long long a1,r1,a2,r2,c,d,x,y;
bool flat;
while(scanf("%d",&n)!=EOF)
{
flat=false;
scanf("%lld%lld",&a1,&r1);
for(int i=1;i<n;i++)
{
scanf("%lld%lld",&a2,&r2);
if(flat)continue;
c=r2-r1;
d=exgcd(a1,a2,x,y);
if(c%d)
{
flat=true;
continue;
}
x*=c/d;
a2/=d;
x=(x%a2+a2)%a2;
r1=r1+x*a1;
a1*=a2;
}
if(flat)puts("-1");
else printf("%lld\n",r1);
}
return 0;
}