数论
数论
牛顿迭代法
将算出的x[n]不断带入x[n-1]的位置重新计算,使x的值处于答案要求的精确度范围即可
算数基本定理
1.自然数N(N>1)可以被分解为n个质数p_k(1...n)的a_k(1...n)次方相乘
2.每个自然数N最多只有一个超过sqrt(N)的因数
反证法,如果有两个以及以上的因数超过sqrt(N),那么则相乘大于N
因此在将N分解为多个质因数相乘的时候可以这样编程
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
while (n--)
{
long long a;
cin >> a;
for(int i=2;i<=a/i;i++ )//因为只有最多一个因数>sqrt(N),所以i<=a/i (1)
{ //不过a是变动的,每次a都会除掉一个质数p_k(1...n)的a_k(1...n)次方(2)
//每次将p_k(1...n) a_k(1...n)次方除完以后输出,之后剩下来的数的因数大小不大于当前的i
//因为小于i的质因数都被除尽了 见(2),然后也符合(1),这样能把问题从求N,变成求N/p1_a1.... //以此类推
int countn=0;
if(a%i==0)
{
while(a%i==0)
{
a/=i;
countn++;
}
printf("%d %d\n",i,countn);
}
}
if(a>1) //如果有没有除尽的因数那就是那个唯一的因数>sqrt(N)
printf("%d 1\n",a);
printf("\n");
}
return 0;
}
质数筛法
//埃氏筛 O(nloglogn) 小数据完爆欧拉筛
int vis[MAXN], prime[MAXN], p = 0;
void primea()
{
//memset(vis,0,sizeof(vis));
//memset(prime,0,sizeof(prime));
vis[1] = 1;
for (int i = 2; i <= MAXN; i++)
if (!vis[i])
{
prime[++p] = i;
for (int j = i * i; j <= MAXN; j += i) //把i的倍数全标记为合数,因为其(2~i-1)倍已经被标记,所以从i倍开始
vis[j] = 1;
}
}
//欧拉筛 线性筛 O(n)数据大的时候会比较优
#define MAXN (int)10e6+5
long long isprime[MAXN],prime[MAXN],countn=0;
void primeo(int n)
{
for(int i=2;i<=n;i++)
{
if(!isprime[i])
{
prime[++countn]=i;//首先小于i的合数都是由(质数prime[j]*小于该数的数)(1)组成
//而小于i的数都被(prime[1]*小于i的数 prime[2]*小于i的数....)筛过了,其质因数都包含在小于i的数里面,
//每个质数p都会*(该质数---小于i的数)来筛掉p的倍数,以及*(2---该质数 中的质数)筛掉p的倍数,而p*小于p大于2的合数,也会通过之后的循环筛掉p的倍数
//之后小于p的质数会*大于p小于i的数,从而总能筛掉p的所有倍数
}
for(int j=1;j<=countn&&i*prime[j]<=n;j++)
{
isprime[prime[j]*i]=1;//由于每次i%prime[j]的时候总能够break,因此被筛掉的数的最小质因数不会大于最后一个
//prime[j],否则在被筛的i*prime[j]的最小质因子不是prime[j],
//而是i中的某个已经被遍历过的因子,则会被不同因子重复筛掉
if(i%prime[j]==0)
break;
}
}
}
模运算规则
快速幂(取模)
long long ksm(long long a,long long b,long long p)
{
long long sum=1;
while(b)
{
if(b&1)
{
sum*=a%p;
sum%=p;
b--;
}
a%=p;
// cout<<a<<"m"<<endl;
a*=a;
// cout<<a<<endl;
b/=2;
}
return sum;
}
费马定理
同余恒等式求逆元
题目条件:m为质数
1.a与 m互质时a可以消去 ①--->②
2.③式成立的前提是m与b互质,将bp-2分离出作为逆元,若m与b不互质则无逆元因为m为质数,b与其唯一可能非1公因数是m,若不互质则bp-1%m==0≠1
2.在一个群内一种运算单位元e唯一,因此此时e恒等b*b^-1恒等1 在mod p的"条件"下
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
long long a,b,p;
cin>>a>>p;
if(a%p)
cout<<ksm(a,p-2,p)<<endl;
else {
printf("impossible\n");
}
}
return 0;
}
同余式
1.同余式可以逐项相加
若
则
2.同余式可以逐项相乘。
若
,则
同余式两边的数和模可以同时乘上一个整数。
若
,则
4.同余式两边的数和模可以同时被它们任一公约数除。
即不需要m与d是互质,但是要是m中有与ab的公因式d,三个数都消去d
若
,则
如果同余式对于模m成立,那么它对于m的任意约数相等的模d也成立。
若
,则
。
5.如果同余式一边上的数和模能被某个数除尽,则同余式的另一边的数也能被这个数除尽。
若
,则
。
6.同余式一边上的数与模的最大公约数,等于另一边上的数与模的最大公约数。 [2]
若
,则
。
约数个数
给定 n 个正整数 ai,请你输出这些数的乘积的约数个数,答案对 10^9+7 取模。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一个整数 ai。
输出格式
输出一个整数,表示所给正整数的乘积的约数个数,答案需对10^9+7 取模。
数据范围
1≤n≤100
1≤ai≤2×10^9
#include<bits/stdc++.h>
#define MOD int (1e9+7)
using namespace std;
int a[105];
map<int ,long long > v;
int main()
{
int n;
long long sum=1;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
for(int j=2;j<=a[i]/j;j++)
{
if(a[i]%j==0)
{
if(v[j]==0)
v[j]=1;
while(a[i]%j==0)
{
a[i]/=j;
v[j]++;
}
}
}
if(a[i]>1){
if(v[a[i]]==0)
v[a[i]]=1;
v[a[i]]++;
}
}
for(map<int ,long long>::iterator i=v.begin();i!=v.end();i++)
{
sum*=i->second;
sum%=MOD;
// cout<<i->first<<" " <<i->second<<endl;
}
cout<<sum<<endl;
return 0;
}
约数之和
题目同上,但是约数之和
推出公式
此处p_x是质数,是上述所有数乘积分解成质数因数(基于算数基本定理)的结果 a_x是质数因数的次方
第二个式子的推出是通过先加几个然后看规律得到的
背后的原理还是像二项式展开式那样,从每个因子中选择一个p_x^k,然后相乘得到一个约数再加到总和里面(不同的选择产生的约数是唯一的),遍历所有的可能.因此是这样的式子
然后就能用等比数列之和公式来做,
注意取模,由于有除法运算,先判定p-1与m是否互质,若是则可以通过求p-1的逆元 (p-1)^(-1)转换成取模结果一致的乘法运算
否则
欧拉函数
-
p_k为N的质因数
-
φ(N)表示1-N中的与N互质的数
-
本式子来源于N-N/p1-N/p2...+N/(p1p2)+N/(p1p3)...-N/(p1p2p3)
-N/(p1p2p4)...=N(1-1/p1)(1-1/p2)(1-1/p3)...(1-1/p_m)
每次从第k个因式中选择1相当于不将p_k作为分母因数,反之选择1/pk就是作为因数,而式子符号可以由乘入的负号决定
欧拉筛法求欧拉函数
欧拉筛法O(n),可以通过最小质因子*某个倍数筛掉1~n的合数,得到质数,而欧拉函数φ(N)与它的因子的φ(x)有关系,
当φ(N=i*prime[j])
1.i%prime[j]==0
φ(N)=φ(i)*prime[j]
2.i%prime[j]!=0
φ(N)=φ(i)prime[j](prime[j]-1)/(prime[j])
线性方程组
题目描述
已知 n元线性一次方程组。
请根据输入的数据,编程输出方程组的解的情况。
输入格式
第一行输入未知数的个数 n
接下来 n行,每行 n + 1 个整数,表示每一个方程的系数及方程右边的值。
输出格式
如果有唯一解,则输出解(小数点后保留两位小数)。
如果方程组无解输出 -1; 如果有无穷多实数解,输出 0;
当前列:前几列已被消成有唯一元素1,当前正在消的列
选择一行:选择的行应该是未被选择过的行
高斯约旦消元法,从最左列到最右列消元,每次选择一行把它的当前列除成1,然后拿这行通过初等变换去消别的行。
1.注意每次选择当前列元素最大的那行,这样能保证精确度,浮点数精度丢失问题。
2.当前列为i时选定i行作为对比对象,最后将当前列最大的行交换到第i行上,这样可以保证每次对比的是没有使用过的行
3.fabs()浮点数取绝对值,小于某个范围判定为该数
#include <bits/stdc++.h>
#define eps 1e-5
using namespace std;
double a[110][110];
int vis[110];
int n;
void solve()
{
for (int i = 1; i <= n; i++)
{
int m = i;
for (int k = i + 1; k <= n; k++)
{
if (fabs(a[k][i]) > fabs(a[m][i]))
{
m = k;
}
}
if (fabs(a[m][i]) < eps)
continue;
for (int j = 1; j <= n + 1; j++)
swap(a[m][j], a[i][j]);
double temp = a[i][i];
for (int j = 1; j <= n + 1; j++)
{
a[i][j] /= temp;
}
for (int k = 1; k <= n; k++)
{
if (k != i)
{
double t = -(a[k][i] / a[i][i]);
for (int j = 1; j <= n + 1; j++)
{
a[k][j] += t * a[i][j];
}
}
}
}
// for (int j = 1; j <= n; j++)
// {
// for (int i = 1; i <= n + 1; i++)
// {
// cout<<a[j][i]<<" ";
// }
// cout<<'\n';
// }
}
void check()
{
int r = 0;
for (int i = 1; i <= n; i++)
{
bool flag = 0;
for (int j = 1; j <= n; j++)
{
if (fabs(a[i][j] - 0) > eps)
{
r++;
flag = 1;
break;
}
}
if (!flag && fabs(a[i][n + 1] - 0) > eps)
{
printf("-1\n");
return;
}
}
// cout<<r<<endl;
if (r < n)
{
printf("0\n");
return;
}
if (r == n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (fabs(a[i][j] - 0) > eps)
printf("x%d=%.2lf\n", j, a[i][n + 1]);
}
}
return;
}
}
int main()
{
cin >> n;
for (int j = 1; j <= n; j++)
for (int i = 1; i <= n + 1; i++)
{
cin >> a[j][i];
}
solve();
check();
return 0;
}
本文来自博客园,作者:多巴胺不耐受仿生人,转载请注明原文链接:https://www.cnblogs.com/VoidCoderTF/articles/15435462.html

浙公网安备 33010602011771号