主要记录遇到的数学/统计专题和优化方法,不涉及到太难的数论。
排列组合
A(n,k)=(n−k)!n!
C(n,k)=(kn)=k!(n−k)!n!
(kn+k−1)
(kn)=(kn−1)+(k−1n−1)
i=r∑n(ri)=(r+1n+1)
(a+b)n=k=0∑n(kn)an−kbk
k=0∑n(kn)=2nk=0∑n(−1)k(kn)=0(n≥1)
n1!n2!⋯nk!n!
(kn+k−1)
nn!=(n−1)!
初始化组合数
个人比较喜欢使用杨辉三角:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| typedef unsigned long long ull; const int N=101; ull c[N][N]; void init() { for(int i=0;i<=100;i++) { for(int j=0;j<=i;j++) { if(!j||j==i) c[i][j]=1; else c[i][j]=c[i-1][j-1]+c[i-1][j]; } } }
|
Luogu P1246 编码
题目描述
编码工作常被运用于密文或压缩传输。这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数字。
字母表中共有 26 个字母 a,b,c,⋯,z,这些特殊的单词长度不超过 6 且字母按升序排列。把所有这样的单词放在一起,按字典顺序排列,一个单词的编码就对应着它在字典中的位置。
例如:
- a→1;
- b→2;
- z→26;
- ab→27;
- ac→28。
你的任务就是对于所给的单词,求出它的编码。
输入格式
仅一行,被编码的单词。
输出格式
仅一行,对应的编码。如果单词不在字母表中,输出 0。
可以使用组合数进行求解,而不是枚举:
注意到,对于 n 位的组合数,它总共的数量 f(n) 满足:
f(x)=⎩⎨⎧26(226)(225)+(224)+...(22)=(326)...n=1n=2n=3
i=2∑25(2i)=(326)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <bits/stdc++.h> #define endl '\n' using namespace std; typedef long long ll; const int N=6; string str; ll c(int m,int n) { ll a=1,b=1; for(int i=1;i<=n;i++) b*=i; for(int i=m-n+1;i<=m;i++) a*=i; return a/b; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>str; int n=str.length(); for(int i=1;i<n;i++) if(str[i]<=str[i-1]) { cout<<0<<endl; return 0; } ll ans=0; for(int i=1;i<n;i++) ans+=c(26,i); for(int i=0;i<n;i++) for(char j=(i?str[i-1]+1:'a');j<str[i];j++) ans+=c('z'-j,n-i-1); cout<<ans+1<<endl; }
|
最大公约数
1 2 3 4 5 6 7 8 9 10
| int gcd(int a,int b) { return b>0?gcd(b,a%b):a; }
int lcm(int a,int b) { return (a/gcd(a, b))*b; }
|
或者用 C++ <algorithm>
提供的 __gcd()
库。
C++ 17 引入了 std::gcd()
和 std::lcm()
,用于计算最大公约数和最小公倍数。
性质:
[a,b](a,b)=∣ab∣
[a,b,c](a,b,c)=∣abc∣
Luogu P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题
题目描述
输入两个正整数 x0,y0,求出满足下列条件的 P,Q 的个数:
P,Q 是正整数。
要求 P,Q 以 x0 为最大公约数,以 y0 为最小公倍数。
试求:满足条件的所有可能的 P,Q 的个数。
输入格式
一行两个正整数 x0,y0。
输出格式
一行一个数,表示求出满足条件的 P,Q 的个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <bits/stdc++.h> #define endl '\n' using namespace std; typedef long long ll; const int N=1e6+5; int a,b; int ans=0; int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>a>>b; if(a==b) { cout<<1<<endl; return 0; } for(int i=1;i*i<=a*b;i++) { if(!((a*b)%i)&&__gcd(i,a*b/i)==a) ans+=2; } cout<<ans<<endl; }
|
素数筛
板子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const int N=1e8+5; int pri[N],top=0; bool not_prime[N];
void pre(int n) { for(int i=2;i<=n;++i) { if(!not_prime[i]) { pri[top++]=i; } for(int pri_j:pri) { if(i*pri_j>n) break; not_prime[i*pri_j]=true; if (!(i%pri_j)) break; } } }
|