数论练习
几个数论入门题的练习(看y总推荐的几个简单的,就拿来练习试试看)
文章目录
POJ 1365 Prime Land
题目:
题目翻译:
太长了,不知道具体是啥
大致就是每一行输入一堆数,前面一个是质数本身,后面一个是他的指数,最后把所有的数相乘就是x,然后求对x-1的一个序列,序列表示含义和输入的一样(前面一个数是一个质数,后面是他的指数),质数从大到小排序输出。
思路:水题,数据读进去,然后直接唯一分解定理。
代码:
/*POJ 1365*/
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;
#define int long long
#define endl '\n'
vector<int> prime;
bool isPrime[32780];
//线性筛素数
void getPrimes()
{
int n = 32767;
for (int i = 2; i <= n; i++)
{
if (!isPrime[i])
{
prime.push_back(i);
isPrime[i] = true;
}
int m = prime.size();
for (int j = 0; i * prime[j] <= n && j < m; j++)
{
isPrime[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
}
//从行里面得到数字
int getNum(string s)
{
int n = s.size();
int res = 1;
int tmp = 0;
int cnt = 0;
int a, b;
for (int i = 0; i < n; i++)
{
if (s[i] != ' ')
tmp = tmp * 10 + s[i] - '0';
else
{
if (cnt == 1)
{
b = tmp;
res = res * pow(a, b);
cnt = 0;
}
else if (cnt == 0)
{
cnt++;
a = tmp;
}
tmp = 0;
}
}
res = res * pow(a, tmp);
return res;
}
signed main()
{
getPrimes();
while (true)
{
string s;
getline(cin, s);
if (s.size() == 1 && s[0] == '0')
break;
int num = getNum(s) - 1;
map<int, int, greater<int>> mp;
while (num) //唯一分解定理
{
int n = prime.size();
for (int i = n - 1; i >= 0; i--)
{
while (num % prime[i] == 0)
{
mp[prime[i]]++;
num /= prime[i];
}
if (num == 1)
break;
}
if (num == 1)
break;
}
map<int, int>::iterator it;
for (it = mp.begin(); it != mp.end(); it++)
cout << it->first << " " << it->second << " ";
cout << endl;
}
return 0;
}
POJ 2034 Anti-prime Sequences
题目:
题目翻译:
对n ~ m连续的数进行排列,找到最小的一组排列,使得数组中,相邻不大于d位的和为合数。
思路:先筛出所有的素数,然后dfs爆搜。
需要注意的地方:
1、素数数组的大小应该开到10000,n最大1000,d最大10,1000*10。
2、判断的时候,倒着判断,直接累加。
比较简单的一道题,因为数组开太小了T了无数次QAQ。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define endl "\n"
const int max_n = 1010;
vector<int> primes;
vector<int> res;
bool isPrime[max_n * 10];
bool vis[max_n];
//筛素数
void getPrimes()
{
for (int i = 2; i <= max_n * 10; i++)
{
if (!isPrime[i])
primes.push_back(i);
int m = primes.size();
for (int j = 0; i * primes[j] <= max_n * 10 && j < m; j++)
{
isPrime[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
memset(isPrime, 0, sizeof(isPrime));
int n = primes.size();
for (int i = 0; i < n; i++)
isPrime[primes[i]] = true;
}
//判断
bool isok(int d, int x, int index)
{
if (index == 0)
return true;
int sum = x;
int tmp = 0;
for (int i = index - 1; i >= 0; i--)
{
sum += res[i];
tmp = i;
break;
}
for (int j = 2; j <= d; j++)
{
if (isPrime[sum])
return false;
if (tmp > 0)
{
sum += res[tmp - 1];
tmp--;
}
}
return true;
}
bool dfs(int n, int m, int d, int index)
{
if (index == m - n + 1)
return true;
for (int i = n; i <= m; i++)
{
if (!vis[i] && isok(d, i, index))
{
res[index] = i;
vis[i] = true;
if (dfs(n, m, d, index + 1))
return true;
vis[i] = false;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
getPrimes();
int n, m, d;
while (cin >> n >> m >> d)
{
if (n == 0 && m == 0 && d == 0)
break;
memset(vis, 0, sizeof(vis));
res.resize(m - n + 1);
if (dfs(n, m, d, 0))
{
int k = res.size();
for (int i = 0; i < k; i++)
{
cout << res[i];
if (i != k - 1)
cout << ",";
}
cout << endl;
}
else
cout << "No anti-prime sequence exists." << endl;
}
return 0;
}
POJ 2407 Relatives
题目:
题目翻译:
求n以内与n互质的数的个数。
思路:欧拉函数。需要注意的就是数据范围1e9。
代码:
#include <iostream>
using namespace std;
int euler(int n)
{
int rea = n;
for (int i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
rea = rea - rea / i;
while (n % i == 0)
n /= i;
}
}
if (n > 1) //最后一个素数
rea = rea - rea / n;
return rea;
}
int main()
{
int n;
while (cin >> n)
{
if (n == 0)
break;
cout << euler(n) << endl;
}
return 0;
}
POJ 2689 Prime Distance
题目:
题目翻译:
输入一个l和一个r,寻找区间中所有相邻素数的差的最小值和最大值。
思路:因为数据范围特别大,所以使用区间筛素数。
代码
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
const int max_n = 1e6 + 10;
bool isPrime[max_n];
vector<int> primes1;
bool isnPrimes[max_n];
//区间筛素数
void getPrimes(int l, int r)
{
for (int i = 2; i <= max_n; i++)
{
if (!isPrime[i])
{
primes1.push_back(i);
for (int j = max(2LL, (l + i - 1) / i) * i; j <= r; j += i)
isnPrimes[j - l] = true;
}
isPrime[i] = true;
int m = primes1.size();
for (int j = 0; j < m && i * primes1[j] <= max_n; j++)
{
isPrime[i * primes1[j]] = true;
if (i % primes1[j] == 0)
break;
}
}
}
signed main()
{
int l, r;
while (cin >> l >> r)
{
primes1.resize(0);
fill(isnPrimes, isnPrimes + max_n, false);
fill(isPrime, isPrime + max_n, false);
getPrimes(l, r);
vector<int> primes;
if (l == 1)
isnPrimes[0] = true;
for (int i = l; i <= r; i++)
{
if (!isnPrimes[i - l])
primes.push_back(i);
}
int n = primes.size();
int mi1, mi2, mi3 = 1 << 30;
int ma1, ma2, ma3 = 0;
for (int i = 1; i < n; i++)
{
if (primes[i] - primes[i - 1] > ma3)
{
ma1 = primes[i - 1];
ma2 = primes[i];
ma3 = ma2 - ma1;
}
if (primes[i] - primes[i - 1] < mi3)
{
mi1 = primes[i - 1];
mi2 = primes[i];
mi3 = mi2 - mi1;
}
}
if (ma3 != 0)
cout << mi1 << "," << mi2 << " are closest, " << ma1 << "," << ma2 << " are most distant." << endl;
else
cout << "There are no adjacent primes." << endl;
}
return 0;
}
POJ 2739 Sum of Consecutive Prime Numbers
题目:
题目翻译:
输入一个数,使用n个连续的素数将它表示出来,每有一种表示方法,结果加1。
思路:水题。打表暴力。
代码:
#include <iostream>
#include <vector>
using namespace std;
const int max_n = 1e4 + 10;
vector<int> primes;
bool isPrime[max_n];
void getPrimes()
{
for (int i = 2; i <= max_n; i++)
{
if (!isPrime[i])
primes.push_back(i);
int m = primes.size();
for (int j = 0; j < m && i * primes[j] <= max_n; j++)
{
isPrime[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
}
int main()
{
getPrimes();
int n;
while (cin >> n)
{
if (n == 0)
break;
int m = primes.size();
int cnt = 0;
for (int i = 0; i < m; i++)
{
int sum = 0;
for (int j = i; j < m; j++)
{
sum += primes[j];
if (sum == n)
{
cnt++;
break;
}
else if (sum > n)
break;
}
}
cout << cnt << endl;
}
return 0;
}
POJ 3126 Prime Path
题意:
输入两个四位数,每次只能改变一个数字,要求从第一个数变成第二个数最小步骤是多少,中间可以变得数只能是质数。
思路:筛素数然后bfs。
注意的地方:宽搜的时候去枚举每一位数字,判断那个数是否是素数,不要直接去枚举素数。直接枚举素数会T的亲妈都不认得。(感觉正常人应该都是这么写的,不知道自己刚开始为什么会直接去枚举素数)
代码:
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
const int max_n = 1e4;
#define endl "\n"
vector<int> primes;
bool isPrime[max_n];
struct STATE
{
int num;
int step;
STATE(){};
STATE(int _num, int _step) { num = _num, step = _step; };
};
void getPrimes()
{
for (int i = 2; i <= max_n; i++)
{
if (!isPrime[i])
primes.push_back(i);
int m = primes.size();
for (int j = 0; j < m && i * primes[j] <= max_n; j++)
{
isPrime[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
}
int bfs(int st, int ed)
{
set<int> sat;
STATE t(st, 0);
queue<STATE> q;
q.push(t);
while (q.size())
{
STATE s = q.front();
q.pop();
if (s.num == ed)
return s.step;
if (sat.count(s.num))
continue;
sat.insert(s.num);
//对每一位进行枚举
for (int i = 0; i <= 9; i++)
{
int tmp = s.num / 10 * 10 + i;
if (!sat.count(tmp) && !isPrime[tmp])
{
STATE t1(tmp, s.step + 1);
q.push(t1);
}
tmp = s.num / 100 * 100 + i * 10 + s.num % 10;
if (!sat.count(tmp) && !isPrime[tmp])
{
STATE t1(tmp, s.step + 1);
q.push(t1);
}
tmp = s.num / 1000 * 1000 + i * 100 + s.num % 100;
if (!sat.count(tmp) && !isPrime[tmp])
{
STATE t1(tmp, s.step + 1);
q.push(t1);
}
if (i == 0)
continue;
tmp = i * 1000 + s.num % 1000;
if (!sat.count(tmp) && !isPrime[tmp])
{
STATE t1(tmp, s.step + 1);
q.push(t1);
}
//cout << tmp << " " << endl;
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
getPrimes();
int t;
cin >> t;
while (t--)
{
int st, ed;
cin >> st >> ed;
int res = bfs(st, ed);
if (res == -1)
cout << "Impossible" << endl;
else
cout << res << endl;
}
return 0;
}
POJ 3518 Prime Gap
题意:
输入一个n,输出包含n的最长连续合数的个数。如果n是质数或者没有,就输出0。
思路:线性筛,然后枚举输出,大水题。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int max_n = 1299709 + 10;
vector<int> primes;
bool isPrime[max_n];
void getPrimes()
{
for (int i = 2; i < max_n; i++)
{
if (!isPrime[i])
primes.push_back(i);
int m = primes.size();
for (int j = 0; j < m && primes[j] * i < max_n; j++)
{
isPrime[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
}
int main()
{
getPrimes();
int n;
while (cin >> n)
{
bool isok = false;
if (n == 0)
break;
int m = primes.size();
for (int i = 0; i < m - 1; i++)
{
if (primes[i] < n && primes[i + 1] > n)
{
isok = true;
cout << primes[i + 1] - primes[i] << endl;
break;
}
}
if (!isok)
cout << "0" << endl;
}
return 0;
}
总结
题才写了3个就开始总结了就离谱
以后做到题了再补上。
应该听学长的话,难的不会,简单的不出(
题目写完了,这次写的都是一些简单的题,重点知识就是线性筛和欧拉函数了。