例题:等差数列 辗转相除gcd
思路:求数组的最大公约数
等差数列 https://www.acwing.com/problem/content/1248/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
#define INF 0x3f3f3f3f
typedef long long ll;
int a[maxn],b[maxn];
int gcd(int m,int n){
if(n == 0) return m;
return gcd(n, m % n);
}
int main()
{
int n,m;
cin>>n;
int f = 1;
for(int i = 1; i <= n; ++i){
cin>>a[i];
if(a[i] != a[1])
f = 0;
}
if(f) {
cout<<n<<endl;
return 0;
}
sort(a+1,a+1+n);
for(int i = 1; i <= n; ++i)
b[i - 1] = abs(a[i] - a[i - 1]);
// cout<<gcd(70,20);
int ans = b[1];
for(int i = 1;i < n;i++){
// cout<<b[i]<<" "<<ans<<" ";
ans = gcd(b[i],ans);
// cout<<ans<<endl;
}
cout<<abs(a[n] - a[1]) / ans + 1<<endl;
return 0;
}
例题:X的因子链
例题https://www.acwing.com/problem/content/1297/
知识点:
算数基本定理——因式分解定理
可重复组合(多重集合组合数)
多重集合排列数
从有n个不同元素的集合任取r个元素的排列方式有:
P
(
n
,
r
)
=
n
∗
(
n
−
1
)
∗
.
.
.
∗
(
n
−
r
+
1
)
=
n
!
(
n
−
r
)
!
P(n, r) = n*(n-1)*...*(n-r+1) = \frac{n!} { (n-r)!}
P(n,r)=n∗(n−1)∗...∗(n−r+1)=(n−r)!n!
特别地
P
(
n
,
n
)
=
n
!
P(n,n) = n!
P(n,n)=n!
或者
M
=
{
k
1
⋅
a
1
,
k
2
⋅
a
2
,
⋯
,
k
n
⋅
a
n
}
M=\{k_1⋅a_1,k_2⋅a2,⋯,k_n⋅a_n\}
M={k1⋅a1,k2⋅a2,⋯,kn⋅an}
(其中每个
a
i
a_i
ai代表是不同的元素,每个元素
a
i
a_i
ai有
k
i
k_i
ki个,
k
i
k_i
ki可以是有限数,也可以是∞。)
多重集合 M = k 1 ⋅ a 1 , k 2 ⋅ a 2 , ⋯ , k n ⋅ a n M={k_1⋅a_1,k_2⋅a2,⋯,k_n⋅a_n} M=k1⋅a1,k2⋅a2,⋯,kn⋅an的 r r r排列数为 k r kr kr
多重集合 M = { k 1 ⋅ a 1 , k 2 ⋅ a 2 , ⋯ , k n ⋅ a n } M =\{k_1⋅a_1,k_2⋅a2,⋯,k_n⋅a_n\} M={k1⋅a1,k2⋅a2,⋯,kn⋅an}的全排列数为: ( k 1 + k 2 + ⋯ + k n ) ! k 1 ! k 2 ! ⋯ k n ! \frac{(k1+k2+⋯+kn)!}{k1!k2!⋯kn!} k1!k2!⋯kn!(k1+k2+⋯+kn)!
素数筛 线性筛
线性筛板子:
int pri[N+9>>1],now;
bool vis[N+9];
void init(){
for(int i=2;i<=N;i++){
if(!vis[i])pri[++now]=i;
for(int j=1;j<=now&&pri[j]*i<=N;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0)break;
}
}
}
代码(分解质因数版):
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1500005;
#define INF 0x3f3f3f3f
typedef long long ll;
int vis[maxn];
ll answer = 1;
ll cal(int x){
ll res = 1;
for(int i = 1;i <= x ;i++)
res *= (1ll*i);
return res;
}
int main()
{
int x;
while(cin>>x){
int sum = 0,tot = 0 ;
// ans.clear();
// memset(vis,0,sizeof(vis));
for(int i = 2;i * i <= x; i++){
vis[++sum] = 0;
while (x % i == 0)
{
x /= i;
vis[sum]++;
tot++;
}
}
if(x != 1){
vis[++sum] = 0;
vis[sum]++;
tot++;
}
answer = cal(tot);
// cout<<sum<<" "<<answer<<endl;
for(int i = 1;i <= sum ; ++i){
for(int j = 1;j <= vis[i] ;++j)
answer /= j;
}
cout<<tot <<" "<< answer<<endl;
}
return 0;
}
例题:聪明的燕姿
N = p 1 a 1 ∗ p 2 a 2 ∗ ⋅ ⋅ ⋅ ∗ p n a n N=p_1^{a_1} * {p_2}^{a_2}*···*p_n^{a_n} N=p1a1∗p2a2∗⋅⋅⋅∗pnan(其中一系列 a n a_n an为指数, p n p_n pn为质数)
约数个数
约数个数 ( a 1 + 1 ) ( a 2 + 1 ) … … ( a n + 1 ) (a_1+1)(a_2+1)……(a_n +1) (a1+1)(a2+1)……(an+1)
约数之和
约数之和 ( 1 + p 1 1 ∗ + p 1 2 + ⋅ ⋅ ⋅ + p 1 a 1 ) ∗ ⋅ ⋅ ⋅ ∗ ( 1 + p k 1 ∗ + p k 2 + ⋅ ⋅ ⋅ + p k a k ) (1+{p_1}^{1} *+{p_1}^{2}+···+{p_1}^{a_1})*···*(1+{p_k}^{1} *+{p_k}^{2}+···+{p_k}^{a_k}) (1+p11∗+p12+⋅⋅⋅+p1a1)∗⋅⋅⋅∗(1+pk1∗+pk2+⋅⋅⋅+pkak)
例题:五指山
裴蜀定理
exgcd板子
int exgcd(int a,int b,int &x,int &y)//扩展欧几里得算法
{
if(!b)
{
x=1;y=0;
return a; //到达递归边界开始向上一层返回
}
int r=exgcd(b,a%b,x,y);
int temp=y; //把x y变成上一层的
y=x-(a/b)*y;
x=temp;
return r; //得到a b的最大公因数
}