数论 解题记录

POJ2429
给两个数的gcd和lcm,输出满足条件的使得a+b最小的a和b
对lcm/gcd=ab这个数来讨论,枚举。找到sqrt(ab)周围第一个满足条件的a和b就好
然鹅,dfs。。

除了dfs外都是大数分解模板
注意,prime_factor内存的是无序的所有质因子,如36存的是 3 2 2 3
有序去重套个set就好力

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <ctime>
#include <utility>
using namespace std;
const int max_prime = 1e6;
const int s = 20;
typedef long long ll;
 
vector<ll> factor;
vector<ll> prime_factor;
ll x, y;	//x:gcd, y:lcm
ll multi_mod(ll a, ll b, ll n)
{
    a %= n;
    b %= n;
    ll res = 0;
    while(b)
    {
        if(b & 1)
        {
            res += a;
            if(res >= n) res -= n;
        }
        a <<= 1;
        if(a >= n) a -= n;
        b >>= 1;
    }
    return res;
}
 
ll pow_mod(ll x, ll n, ll mod)
{
    if(n == 1)  return x % mod;
    x %= mod;
 
    ll tmp = x;
    ll res = 1;
    while(n > 0)
    {
        if(n & 1)   res = multi_mod(res, tmp, mod);
        tmp = multi_mod(tmp, tmp, mod);
        n >>= 1;
    }
    return res;
}
 
bool witness(ll a, ll n, ll u, ll t)
{
    ll res = pow_mod(a, u, n);
    ll last = res;
    for(int i = 0; i < t; i++)
    {
        res = multi_mod(res, res, n);
        if(res == 1 && last != 1 && last != n-1)    return true;
        last = res;
    }
    if(res != 1)    return true;
    else        return false;
}
 
bool robin_miller(ll n) //判断是否素数
{
    if(n < 2)    return false;
    if(n == 2)  return true;
    if(!(n & 1))    return false;
 
    ll u = n - 1, t = 0;
    while(!(u & 1)) u >>= 1, t++;
    if(t >= 1 && (u & 1) == 1)
    {
        for(int i = 0; i < s; i++)
        {
            ll a = rand() % (n-1) + 1;
            if(witness(a, n, u, t)) return false;   //不是素数
        }
    }
    return true;    //是素数
}
 
ll gcd(ll a, ll b)
{
    if(a == 0)  return 1;
    if(a < 0)    return gcd(-a, b);
    while(b)
    {
        ll t = a % b;
        a = b;
        b = t;
    }
    return a;
}
 
ll pollard_rho(ll x, ll c)
{
    ll i = 1, x0 = rand() % x;
    ll y = x0;
    ll k = 2;
    for(;;)
    {
        i++;
        x0 = (multi_mod(x0, x0, x) + c) % x;
        ll d = gcd(y - x0, x);  //这里传给gcd的参数可能负数,注意分别讨论
        if(d != 1 && d != x) return d;  //这里表明找到了一个因子
        if(y == x0) return x;
        if(i == k)
        {
            y = x0;
            k += k;
        }
    }
}
 
void find_fac(ll n)
{
    if(n == 1)    return;
    if(robin_miller(n))
    {
        prime_factor.push_back(n);//set.insert(n);
        return;
    }
    ll p = n;
    while(p >= n) p = pollard_rho(p, rand() % (n-1) + 1);
    find_fac(p);
    find_fac(n / p);
}
 
ll dfs(int p, int len, ll res, ll m)
{
	if(res > m)	return 0;
	if(p == len || res == m)	return res;
 
	ll tmp1 = dfs(p+1, len, res, m), tmp2;
	//cout<<tmp1<<endl;
	if(res * factor[p] + 0.0 > m)	return tmp1;
	else
	{
		tmp2 = dfs(p+1, len, res*factor[p], m);
		//cout << tmp1<<" "<<tmp2 <<endl;
		return tmp1 > tmp2 ? tmp1 : tmp2;
	}
}
 
int main()
{
	//freopen("in.txt", "r", stdin);
	while(cin >> x >> y)
	{
		srand(time(NULL));
		prime_factor.clear();
		factor.clear();
 
		y /= x;
		find_fac(y);
		ll tmp = y;
		//		cout<<"prime factor"<<endl;		for(int i = 0; i < prime_factor.size(); i++){			cout<< prime_factor[i]<<" ";		} cout<<endl;
		
		
		
		for(int i = 0; i < prime_factor.size(); i++)
		{
			ll res = 1;
			while(tmp % prime_factor[i] == 0)
				res *= prime_factor[i], tmp /= prime_factor[i];
			//cout << res<<" ";
			if(res != 1)	factor.push_back(res);
		}
		
		//cout<<"factor : ";	for(int i =0; i < factor.size(); i++){			cout<<factor[i]<<" ";		}cout<<endl;
 
		int len = factor.size();
		ll m = (ll)sqrt(y + 0.0);
		ll a = dfs(0, len, 1, m);
		ll b = y / a;
		printf("%lld %lld\n", a * x, b * x);
	}
	return 0;
}

POJ1930
据说是小学奥数题,为什么我上了大学还要活在小学成绩不好的阴影里QAQ
结论还是有用的吧,大概(但是谁要是出这题不是无聊么)

①完全循环小数
分母=循环节长度个9
如0.19191919 即分母为99
②混合小数
懒得写了,反正最后就是
0.12368686868=(12368-123)/99000
代码不打了耶耶耶(过分

POJ3126
每次只改变一个数且改变后也必须是素数,把一个素数a变成另一个素数b。问最少需要多少布
本来还以为可以趁机学习数位DP!
结果dp不好写最后直接bfs了QAQ

#include<iostream>
#include<cstring> 
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e6 + 5 ;
int INf = 0x3f3f3f3f;
bool isprime[N];

int prime[1050];
void init() 
{
	memset(isprime,true,sizeof(isprime));
	isprime[0]=isprime[1]=false;
	isprime[2]=true;
	for(int i = 2; i < N ;i++)
	{
		if(!isprime[i]) continue;
		for(int j = 2; i*j< N;j++)
		{
			isprime[i*j]=false;
		}
	}
}
int vis[10000];
int step[10000];
int bfs(int a,int b)
{
	
	int xx = a, yy = b;
	queue<int> q;
	memset(vis, 0, sizeof (vis));
	memset(step, 0, sizeof (step));
	
	q.push(a);
	vis[a]=1;
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		if(x == b)
		{
			return step[x];
		}
		xx=x-x%10;
		for(int i= 0; i<= 9;i++)
		{	
			//cout<<xx<<endl; 
			if(isprime[xx]&&!vis[xx])
			{
				vis[xx] = 1;
				q.push(xx);
				step[xx] = step[x] + 1;
				//cout<<"push"<<endl;
			}
			xx++;
			
		}
		xx = x - x%100 + x%10;
		for(int i = 0; i<= 9 ; i++)
		{
			//cout<<xx<<endl;
			if(isprime[xx]&&!vis[xx])
			{
				vis[xx] = 1;
				q.push(xx);
				step[xx]=step[x] + 1;
				//cout<<xx<<endl;
			}
			xx+=10;
		}
		xx = x - x%1000 + x%100 ;
		for(int i = 0; i<= 9 ; i++ )
		{
			
			//cout<<xx<<endl;
			if(isprime[xx] && !vis[xx])
			{
				vis[xx] = 1;
				q.push(xx);
				step[xx]=step[x] + 1;
				//cout<<xx<<endl;
			}
			xx+=100;
		}
		xx = 1000 + x%1000;
		for(int i = 0; i< 9 ; i++)
		{
			//cout<<xx<<endl;
			if(isprime[xx] && !vis[xx])
			{
				q.push(xx); 
				vis[xx] = 1;
				step[xx]=step[x] + 1;
				//cout<<xx<<endl;
			} 
			xx+=1000;
		}
	}
	
}
int main()
{
	init();
	int t, l, r;
	int cnt = 0;
	for(int i=2;i<=150;i++) if(isprime[i])cout<<i<<",";
	cin>>t;
	while(t--)
	{
		cin>> l >> r;
		cout<<bfs(l,r)<<endl;
	}
	return 0;
}

POJ3421
智商题
当找不到规律的时候,就质因数分解试试。
注意质因数分解不要先打素数表,用map存还挺香,这个数据是2^20的多组数据1s的,直接写可以过

#include<map>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N = 1e6 ;
ull p[23];
ll prime[23] = {
	2,3,5,7,11,13,17,19,23,29,
	31,37,41,43,47,53,59,61,67,71,
	73,79,83
};
void init()
{
	p[1] = 1;
	for ( ull i=2; i <= 23 ; i++ )
	{
		p[i] = p [i-1]*i;
	}
}
map<ll,ll> factor;
int cnt = 0;
void find_factor(ll x)
{
	for(int i=2 ;i*i<=x  ; i++)
	{

		while( x%i == 0 )
		{
			//cout<<"push: "<<i<<endl;
			x /= i;
			factor[i]++;
		}
		
	}
	if(x!=1)
		factor[x]++;
}
int main()
{
	ll a;
	init();
	while( cin>>a )
	{
		factor.clear();
		find_factor(a);
		//cout<<factor.size()<<" ";
		ll ans = 1;
		ll sum = 0;
		map<ll,ll>::iterator I;
		I = factor.begin();
		while(I!=factor.end())
		{
			sum += I->second ;
			//cout <<I.first<<" "<<I.second<<endl;
			ans *= p[I->second] ;
			I++;
		}
		//cout<<sum<<endl<<ans<<endl;
		ans = p[sum]/ans;
		cout<<sum<<" "<<ans<<endl;
	}
	return 0;
}

POJ3292
后面两道题都是快速幂,基本是板子orz

快速幂模板

ull qp(ull x,ull n,ull mod){
	ull res = 1;
	while(n>0)
	{
		if(n&1)
		{
			res =(res*x)%mod;
		}
		x =(x*x)%mod;
		n >>= 1;
	}
	return res;
}

题目:
POJ3641

#include<iostream>
using namespace std;
const int mod=1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
bool prime(ull a){
	if (a==1) return false;
	if (a==2) return true;
	for (ull i=2;i*i<a;i++)
	{
		if(a%i==0) return false;
	}
	return true;
}
ull qp(ull x,ull n,ull mod){
	ull res = 1;
	while(n>0)
	{
		if(n&1)
		{
			res =(res*x)%mod;
		}
		x =(x*x)%mod;
		n >>= 1;
	}
	return res;
}
int main()
{
	ull a,p;
	while(cin>>p>>a && a+p!=0)
	{
		//cout<<qp(a,p,p)<<endl;
		if(qp(a,p,p)==a%p)
			if(!prime(p))
			{
				puts("yes");
				continue;
			}
		puts("no");
	}
	return 0;
}

POJ1995

#include<iostream>
using namespace std;
const int mod=1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
bool prime(ull a){
	if (a==1) return false;
	if (a==2) return true;
	for (ull i=2;i*i<a;i++)
	{
		if(a%i==0) return false;
	}
	return true;
}
ull qp(ull x,ull n,ull mod){
	ull res = 1;
	while(n>0)
	{
		if(n&1)
		{
			res =(res*x)%mod;
		}
		x =(x*x)%mod;
		n >>= 1;
	}
	return res;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		ull a,b,sum=0,m,h;
		cin>>m>>h;
		for(int i=0;i<h;i++)
		{
			cin>>a>>b;
		
			//cout<<qp(a,b,m)<<endl;
			sum+=qp(a,b,m);
			sum%=m;
		}
		cout<<sum<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值