五一培训第二天
一 素数
今天先来回顾一下之前学过的素数(质数),当n是质数时,以下两个式子,至少有一个是成立的
1.a的d次方 % n == 1
2.存在一个i,0 <= i < r,a的d乘2的i次方的次方 % n == n - 1
那我们怎样用它判断素数呢?
如果一定成立
如果可能成立,可能不成立
--- 如果不成立,为合数
--- 如果成立,再算,再成立,再算
--- 如果一直成立,不保证100%,但是99.999%
--- 要是错了,去买彩票吧...
总结就是,miller_rabin算法用了极其微小的正确率,换来了更加优秀的时间复杂度
#include<bits/stdc++.h>
using namespace std;
int ksm(int a,int b,int p){
if(b == 0) return 1%p;
int c=ksm(a,b/2,p);
c=1ll*c*c%p;
if(b % 2 == 1) c=1ll*c*a%p;
return c;
}
bool miller_rabin(int n,int a){//O(log n)
int d=n-1,r=0;
while(d % 2 == 0){
d=d/2;
r=r+1;
}
int v=ksm(a,d,n);
if(v == 1) return true;//若第一条满足,return ture
for(int i=0;i<r;i++){
if(v == n-1) return true;//若第二条满足,return true
v=(__int128)v*v%n;//没有必要写快速幂,不断的平方就好了
}
return false;
}
bool is_prime(int n){
if(n < 2) return false;
if(n == 2) return true;
for(int i=1;i<=20;i++){
int a=rand() % (n-1)+1;//赌徒,随机赋值
if(miller_rabin(n,a) == false) return false;
}
return true;
}
int prime_list[10]={2,3,5,7,11,13,17,19,31,97};
bool is_prime2(int n){
if(n < 2) return false;
for(int i=0;i<10;i++){
if(n == prime_list[i]) return true;
if(n % prime_list[i] == 0) return false;
if(miller_rabin(n,prime_list[i] % n) == false) return false;
}
return true;
}
signed main(){
int n;
cin>>n;
if(is_prime(n) == true) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
if(is_prime2(n) == true) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
那如果换一种形式呢?现在,请你求出1
int not_prime[1010];
void f(int n){//O(nloglog n)
for(int i=2;i<=n;i++){
if(not_prime[i] == false){
for(int j=i+i;j<=n;j+=i){
not_prime[j] = true;
}
}
}
}
可以看出,它的复杂度是O(nloglog n)
,其实已经够用了,但我们还要继续优化——线性筛
#include<bits/stdc++.h>
using namespace std;wq
const int maxn=1000010;
int pcnt,not_prime[maxn],plist[maxn];
signed main(){
int n;
cin>>n;
not_prime[1] = true;
for(int i=1;i<=n;i++){
if(not_prime[i] == false){
pcnt=pcnt+1;
plist[pcnt] = i;
}
for(int j=1;j<=pcnt;j++){
int v=plist[j] * i;
if(v > n) break;
not_prime[v] = true;
if(i % plist[j] == 0){
break;
}
}
}
return 0;
}
二 组合数学
组合数学主要分为加法原理和乘法原理,他们两个的区别就是加法原理不可以同时选,而乘法原理可以同时选,具体看图
现在给你一道题,有n个人,从中选出m个人,而不同的顺序算不同的方案
可得出
很好,那如果不同的顺序算相同的方案呢
可得出
相信聪明的你肯定还可以列出组合数的递推式
有没有感觉这坨东西有点似曾相识,没错,这就是杨辉三角形,看下面
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
三 还是组合数学
在组合数学中,有一类很常见的题目,但他们又有一些其他的分类(待补充)
给定
-
:由于数据范围不大,所以直接用递推式
signed main(){ int t,k; cin>>t>>k; for(int i=0;i<=200;i++){ c[i][0] = 1; for(int j=1;j<=i;j++){ c[i][j]=c[i-1][j-1]+c[i-1][j]; } } cout<<c[t][k]<<'\n'; return 0; }
-
( 为质数,有 次询问, ):可以用公式
。signed main(){ fac[0] = 1; for(int i=1;i<=1000000;i++){ fac[i]=1ll*fac[i-1]*i%p; } for(int i=0;i<=1000000;i++){ ifac[i]=ksm(fac[i],p-2); } for(int i=1;i<=q;i++){ int n,m; cin>>n>>m; int ans=1ll*fac[n]*ifac[m]%p*ifac[n-m]%p; cout<<ans<<endl; } returen 0; }
-
(任意数)可以用程序来实现约分
signed main(){ cin>>n>>m>>p; for(int i=1;i<=m;i++){ fenzi[i] = n-i+1; fenmu[i] = i; } for(int i=1;i<=m;i++){ for(int j=1;j<=m;j++){ int g=gcd(fenzi[i],fenmu[j]); fenzi[i] = fenzi[i] / g; fenmu[j] = fenmu[j] / g; } } int ans=1; for(int i=1;i<=m;i++){ ans=1ll*ans*fenzi[i]%p; } cout<<ans<<endl; return 0; }
-
为质数,有 次询问( ):需要用到Lucas 定理(当
是质数时, )。int C(int n,int m){ if(n < p) return 1ll * fac[n] * ifac[m] % p *ifac[n-m] % p; else return 1ll * C(n%p,m%p) * C(n/p,m/p) % p; } signed main(){ fac[0] = 1; for(int i=1;i<=1000000;i++){ fac[i]=1ll*fac[i-1]*i%p; } for(int i=0;i<=1000000;i++){ ifac[i]=ksm(fac[i],p-2); } for(int i=1;i<=q;i++){ int n,m; cin>>n>>m; int ans=1ll*fac[n]*ifac[m]%p*ifac[n-m]%p; cout<<ans<<endl; } returen 0; }
四 抽屉原理
大概意思就是你先在有
现在,给你一个数
那么,这和抽屉原理有什么关系呢?
我们可以把它看成一个序列,每一个数的位置都有一个前缀和,也就是有
五 容斥原理
要想了解他,先看一道题。
给你一个数
#include<bits/stdc++.h>
using namespace std;
int fac[70];
//fac[i] 代表 x^i这种数 被算了几次了
long long n;
int main()
{
cin >> n;//计算1-n中有多少个数可以表示成x^y,x>1,y>1的形式
long long ans=0;
for (int i=2;i<=64;i++)
{
long long v = floor(pow(n,1.0/i)) - 1;//计算2~n中有多少个数 可以表示成x^i的形式
int d = 1 - fac[i];//代表x^y这种 还应该被算几次
ans += d*v;
for (int j=i;j<=64;j+=i)
fac[j] += d;
}
cout << ans+1 << endl;
//输出时记得加上减去的 1
return 0;
}
六 组合数拆分P4369
现在有这样一道例题,给定你
#include <bits/stdc++.h>
using namespace std;
signed main(){
int x,k;
cin>>x>>k;
for (int i=1;i<k;i++){
cout<<i<<" "<<0<<'\n';
}
cout<<x-k+1<<" "<<1<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!