您的位置:首页 > 其它

不定方程:poj 2142+poj 1091(数论+容斥)

2015-01-27 15:30 274 查看
     二元一次不定方程ax+by=d与同余方程ax=d(mod b)等价,求解线性同余方程可参考链接:http://blog.csdn.net/u012717411/article/details/42869291

poj 2142 The Balance

题目链接:http://poj.org/problem?id=2142

解题思路:扩展欧几里得很容易得到通解x=x0+b0*t,y=y0-a0*t;问题最关键的是找到特解中|x|+|y|最小的那一组(x,y).

对于| x0+b0*t |+ | y0-a0*t | 取最小值,很容易想到x,y至少有一个是最小非负整数解(x,y至少一个为正且越靠近0才有最小值),所以比较一下两种情况取最小值即可。

参考代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 50;
ll a,b,d,t,x,y,vx,vy;
ll extended_gcd(ll a,ll b,ll &x,ll &y)
{
if(b==0) {x=1;y=0;return a;}
ll d=extended_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
//  freopen("input.txt","r",stdin);
while(cin>>a>>b>>d&&(a+b+d)){
t=extended_gcd(a,b,x,y);
vy=((y*d/t)%(a/t)+(a/t))%(a/t);//vy最小非负整数解
vx=(d-b*vy)/a;if(vx<0) vx=-vx;  //ax+by=c,vy对应的vx
x=((x*d/t)%(b/t)+(b/t))%(b/t);//x最小非负整数解
y=(d-a*x)/b; if(y<0) y=-y;    //ax+by=c,x对应的y
if(x+y>vx+vy) {x=vx;y=vy;}
cout<


poj 1091 跳蚤

题目链接:http://poj.org/problem?id=1091

解题思路:对于n元一次不定方程a1x1+a2x2+……+anxn=d有解的充要条件是(a1,a2,…,an)|d。

本题求n个不超过m的数a1,a2,…,an的组合个数,要求它们的最大公约数gcd(a1,a2,…,an)=1。

参考题解:
http://www.cnblogs.com/DrunBee/archive/2012/09/07/2674602.html(理解容斥定理) http://blog.csdn.net/yitiaodacaidog/article/details/15462857(所包含的众多知识点)
参考代码+部分注释:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 50000;
ll n,m,ans,t,x,fac[50],a[50],temp;
ll quickpow_mod(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=ans*a;
b>>=1;
a=a*a;
}
return ans;
}
void divide(ll m)     //分解素因子,存于fac[];
{
for(int i=2;i*i<=m;i++){
if(m%i==0){
fac[t++]=i;
while(m%i==0) m/=i;
}
}
if(m>1) fac[t++]=m;
}
void dfs(int pos,int cnt,int num) //dfs得到卡片中n+1个数有num个公因子时的方法数
{
if(cnt==num){
x=m;
for(int i=0;i>n>>m){
ans=0;t=0;
divide(m);
for(int i=1;i<=t;i++){
temp=0;
dfs(0,0,i);       //求解n+1个数有i个公因子的组合数,返回值temp
if(i&1) ans+=temp;
else ans-=temp;
}
cout<
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息