中国矿业大学数据结构实验(1)
A 找新朋友
考察欧拉函数\(\phi(n)\):\([1,n]\)中与\(n\)互质的数的个数
欧拉函数性质:
(1)当\(p\)为质数时,\(\phi(p)=p-1\)
(2)当\(p\)为质数时,$ \phi(p^k) = (p-1) p^{k-1}$
证明:考虑把整数\([1,p^{k}]\) 分解为\([1,p]+[p+1,p^2]+\dots+[p^{k-1}+1,p^k]\)共\(p^{k-1}\)个区间
每个区间都有\(p-1\)个数和\(p^{k}\)互质,易得$ \phi(p^k) = (p-1) p^{k-1}$
(3)当\(n\)和\(m\)互质时,\(\phi(mn)=\phi(m)*\phi(n)\)
证明:两个数互质,不存在共同的因数,结果是显然的
欧拉函数的计算
根据唯一分解定理:\(n=p_1^{a_1}\times p_2^{a_2} \times \dots p_s^{a_s}\)
结合欧拉函数的三条性质可得:\(\phi(n)= \displaystyle{\prod_{i=1}^s\phi(p_i^{a_i})=\prod_{i=1}^s(p_i-1)p^{a_i-1}=\prod_{i=1}^sp_i^{a_i}\frac{p_i-1}{p_i}=n\times\prod_{i=1}^s\frac{p_i-1}{p_i}}\)
欧拉筛
用筛法求\(n\)以内的质数,时间复杂度是线性的,保证每个合数都被他的最小质因数筛去,具体流程为
- 遍历\([1,n]\),如果当前的\(i\)没有被打上标记,说明\(i\)是质数
- 从小到大遍历当前找到的质数\(p[j]\in p[1,cnt]\)
- 若\(p[j]\)是\(i\)的因数:终止遍历,因为\(i\times p[j+1]\)的最小质因数是\(p[j] < p[j+1]\),(\(i\times p[j+1]\)会被后面更大的\(i\)和\(p[j]\)筛去)
- 若\(p[j]\)不是\(i\)的因数:给\(i\times p[j]\)打上标记
筛法求欧拉函数
原理同欧拉筛,因为欧拉函数就是用质因数计算的,可以找到\(n\)的欧拉函数和\(n\)的最小质因数\(p[j]\)的欧拉函数的关系
- 若\(p[j]\)是\(i\)的因数:终止遍历,同时\(\phi(n)=p[j]\times \phi(i)\)
- 若\(p[j]\)不是\(i\)的因数:给\(i\times p[j]\)打上标记,同时\(\phi(n)=(p[j]-1)*\phi(i)\)
void Eulor(int n)
{
phi[1] = 1;
for(int i = 2 ; i <= n ; i ++)
{
if(vis[i] == 0) phi[i] = i-1,p[cnt++] = i;
for(int j = 0 ; j < cnt && i*p[j] <= n ; j ++)
{
int m = i*p[j];
vis[m] = 1;
if(i % p[j] == 0)
{
phi[m] = p[j]*phi[i];
break;
}
else
{
phi[m] = (p[j]-1)*phi[i];
}
}
}
}
B 互质
A问题的规模不大,可以先离线的算出,再\(O(1)\)进行询问,B题只能用在线的试除法
试除法的原理非常简单:\(n\)若有质因数\(p\),那就一直除以\(p\),直到不能整除为止
void slove(LL n)
{
LL res = n;
for(int i = 2 ; i*i <= n ; i ++)
{
if(n%i == 0) res = res/i*(i-1);
while(n%i == 0) n/= i;
}
//剩下一个大于sqrt(n)的质数
if(n >= 2) res = res/n*(n-1);
cout << res << endl;
}
C 约瑟夫问题
问题规模为\((n,m)\)的约瑟夫问题
(1)模拟法
#include<iostream>
using namespace std;
const int N = 105;
struct Node {
int val;
int next;
int pre;
}Nodes[N];
int main()
{
int n, m;
cin >> n >> m;
Nodes[0].next = 1;
for (int i = 1; i <= n; i++)
{
Nodes[i].val = i;
Nodes[i].next = i + 1;
}
Nodes[n].next = 1;
int now = 1, preN = 1;
while ((n--) > 1)
{
for (int i = 1; i < m; i++)
{
preN = now;
now = Nodes[now].next;
}
cout << Nodes[now].val << ' ';
Nodes[preN].next = Nodes[now].next;
now = Nodes[preN].next;
}
cout << Nodes[now].val;
return 0;
}
(2)递推法
用\(J_{n,m}\)表示问题规模为\((n,m)\)的约瑟夫问题,有如下递推公式:\(J_{n,m}=(J_{n-1,m}+m)\mod n\)
int solve(int n,int m)
{
int p=0;
for(int i=2;i<=n;i++)
{
p=(p+m)%i;
}
return p+1;
}
D 进制转换
不会退学吧
E 整数求和
string的库函数要记得
- 取子串:
string sub = s.substr(起始下标,子串长度) - 查找字符串:
int pos = s.find(字符串) int/long long/doule -> string:to_stringstring -> int:stoi()string -> long long:stoll()string -> double:stod()
void solve(string op)
{
int n = op.size() - 1; // 最后一个字符是=
int pos = op.find("+");
string sub1 = op.substr(0, pos);
string sub2 = op.substr(pos + 1, n - pos - 1);
int num1 = stoi(sub1);
int num2 = stoi(sub2);
int result = num1 + num2;
cout << op << result << endl;
}
E 波兰表达式
(1)字符串流读入数据
#include<iostream>
#include<sstream>
#include<string>
#include<stack>
#include<vector>
using namespace std;
stack<double> op1;
vector<string> v;
int main()
{
string op, x;
getline(cin, op);
istringstream ss(op);
// 将输入分割为标记并存储到vector中
while (ss >> x)
{
v.push_back(x);
}
// 逆序处理vector中的每个元素(从右到左)
for (int i = v.size() - 1; i >= 0; i--)
{
if (v[i] == "+")
{
double a = op1.top(); op1.pop();
double b = op1.top(); op1.pop();
op1.push(a + b);
}
else if (v[i] == "-")
{
double a = op1.top(); op1.pop();
double b = op1.top(); op1.pop();
op1.push(a - b); // 注意操作数顺序:a - b
}
else if (v[i] == "*")
{
double a = op1.top(); op1.pop();
double b = op1.top(); op1.pop();
op1.push(a * b);
}
else if (v[i] == "/")
{
double a = op1.top(); op1.pop();
double b = op1.top(); op1.pop();
op1.push(a / b);
}
else {
op1.push(stod(v[i]));
}
}
cout << op1.top() << endl; // 输出最终结果(小数什么的自己搞)
return 0;
}
(2)递归解法(学长的超牛解法,原文学长的代码)
#include<bits/stdc++.h>
using namespace std;
double dp()
{
char a[30];
cin>>a;
switch (a[0]){
case '+':return dp() + dp();
case '-':return dp() - dp();
case '*':return dp()*dp();
case '/':return dp() / dp();
default:return atof(a); //atof函数能将char转换为double
}
}
int main()
{
printf("%.6f",dp());
}
F 合并队列
简单的二路归并,不想写了

浙公网安备 33010602011771号