11.25闲话
碱和盐生成新言和新碱
酸和盐生成新言和新酸
酸和碱生成言和水
酸和金属氧化物生成言和水
碱和非金属氧化物生成言和水
酸和金属生成言和氢气
言和盐生成新言和新盐
言和金属生成新言和新金属
推歌,听我一言
今天言和成分较高
途经千家檐 身携清风入世间
逍遥孤飞燕 请诸君听我一言
不用 滥竽旧弦
去重弹老调陈言
闯天涯只需手边
奏出江湖快雨的琴键
不屑 一律千篇
框定我的纷扰流言
劲装红颜 前所未见
就睁大双眼
若你有意来聆听 保证能耳目一新
怀藏匣里龙吟 路遇不平则鸣
问天下 谁可叱咤风云
自报狂徒姓名
用世风 打磨话语的机锋
普通的人 声音各有各的不同
我走过 岁月峥嵘
踏歌红尘之中
抱琴对群贤 聚谈世情多少面
说玄论典 吟啸谢知音
言无不尽 知无不言
言道 刺骨笔锋 更胜刀剑
出将入相 戏台上演
一战冠绝华山巅
人间传奇几篇
歌 玉楼十二 大道三千
起卦阴阳勘机缘
万代千秋巨浪里
人奋楫向前
和鸣战鼓又一遍
拎着速食的人群熙攘
谁敢高喊自我的主张
我 要单向宣战与缄默对抗
掀起真心共振的音浪
千军万马难以阻挡
怕只怕 高处不胜寒
在台上 飒不飒 观众说了算
梦袭来 画就画 别等到灵感枯干
来者任凭你
怎么谱曲 怎么著词句
怎么调律 怎么着色画皮
嘿 麦克接招演绎
唱我 唱他唱你 哈哈
什么情谊 什么大道理
什么侠义 什么少年志气
嘿 发声百无禁忌
歌喉从不被拘泥
途经千家檐 身携清风入世间
(抱琴对群贤 龙门阵前)
说玄论典 逍遥孤飞燕
幸会知音 听我一言
(言无不尽 知无不言)
言道 刺骨笔锋 更胜刀剑
出将入相 戏台上演
一战冠绝华山巅
人间传奇几篇
歌 玉楼十二 大道三千
起卦阴阳勘机缘
万代千秋巨浪里
人奋楫向前
和我唱一遍
(刺骨笔锋 更胜刀剑
出将入相 戏台上演)
我唱着包罗万象的歌
泾渭相左在这儿也握手言和
(传奇几篇)
(玉楼十二 大道三千
起卦阴阳勘机缘 啊)
你我皆行客 暂且别过
江湖再见 记住我叫言和
求排列数方法
这个直接求就行
代码如下
inline int A(int n,m){
int ans=1;
for(int i=n-m+1;i<=n;i++)
ans*=i;
return ans;
}
求组合数方法
预处理法/递推/杨辉三角
适用于\(\dbinom{b}{a}\)中\(a,b\)都很小的情况 ( \(a,b\le10^4\))
直接 \(\mathrm O(n^2)\) 预处理出\(\dbinom{b}{a}\)然后用的时候直接 \(\mathrm O(1)\) 查表
void init(){
for(int i=0;i<N;i++)
for(int j=0;j<=i;j++)
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
乘法逆元
根据计算公式,\(\dbinom{b}{a}=\dfrac{n!}{m!\times(n-m)!}\)可以直接求出,但是问题来了,除法不能\(\bmod q\),所以要先求\((m!\times(n-m)!)^{-1}\)
用费马小定理和快速幂就行
接下来就能直接求了
代码
int fact[N],Inverse[N];
inline int qpow(int a,int k,int p){
int res=1;
while(k){
if(k&1) res=res*a%p;
k>>=1;
a=a*a%p;
}
return res;
}
inline int solve(int n,int m){
return fact[a]*Inverse[a-b]%mod*Inverse[b]%mod;
}
signed main(){
fact[0]=Inverse[0]=1;
for(int i=1;i<N;i++){
fact[i]=fact[i-1]*i%mod;
}
Inverse[N-1]=qpow(fact[N-1],mod-2,mod);
for(int i=N-2;i>=1;i--)
Inverse[i]=Inverse[i+1]*(i+1)%mod;
int n=read(),m=read();
cout<<solve(n,m);
}
Lucas 定理
用于求解一些\(p\)较小 (\(p\le 10^6\)) 而\(a,b\)范围较大的题 (\(a,b\le 10^{18}\))
对于质数\(p\) ( \(p\)的范围不能太大)
\(n\bmod p\) 和 \(m\bmod p\) 直接求解,
\(\displaystyle\dbinom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\) 继续用 Lucas 定理求解。
边界条件:当 \(m=0\) 的时候,返回 \(1\)
证明:不会(摆)
From OI-Wiki
考虑
\(\displaystyle\binom{p}{n} \bmod p\) 的取值,注意到
\(\displaystyle\binom{p}{n} = \frac{p!}{n!(p-n)!}\) ,分子的质因子分解中 \(p\) 的次数恰好为 \(1\) ,因此只有当 \(n = 0\) 或 \(n = p\) 的时候 \(n!(p-n)!\) 的质因子分解中含有 \(p\) ,因此
。进而我们可以得出
注意过程中没有用到费马小定理,因此这一推导不仅适用于整数,亦适用于多项式。因此我们可以考虑二项式 [fp(x)=(axn + bxm)p \bmod p] 的结果
考虑二项式 \((1+x)^n \bmod p\) ,那么
\(\displaystyle\binom n m\) 就是求其在 \(x^m\) 次项的取值。使用上述引理,我们可以得到
注意前者只有在 \(p\) 的倍数位置才有取值,而后者最高次项为 \(n\bmod p \le p-1\) ,因此这两部分的卷积在任何一个位置只有最多一种方式贡献取值,即在前者部分取 \(p\) 的倍数次项,后者部分取剩余项,即
代码其实很简单
inline int qpow(int a,int k, int p){
int res=1;
while(k){
if(k&1) res=res*a%p;
k>>=1;
a=a*a%p;
}
return res;
}
inline int Comb(int a,int b,int p){
if(a<b) return 0;
int res=1;
for(int i=1,j=a;i<=b;i++,j--)
res=res*j%p,
res=res*qpow(i,p-2,p)%p;
return res;
}
inline int lucas(int a, int b, int p){
if(a<p&&b<p) return Comb(a,b,p);
return Comb(a%p,b%p,p)*lucas(a/p,b/p,p)%p;
}
signed main(){
int a=read(),b=read(),p=read();
cout<<lucas(a,b,p)<<endl;
}
高精度
有的题不让\(\bmod \ p\),所以只好使用高精度了
直接根据定义\(\dbinom{b}{a}=\dfrac{n!}{m!\times(n-m)!}\)求解
先筛出范围内所有质数,接下来对\(\dfrac{n!}{m!\times(n-m)!}\)中的\(n!\)和\(m!\times(n-m)!\)进行质因数分解,然后把这些质因数进行高精乘低精
求\(n!\)中质因子\(p\)出现的次数的公式:
其中\(sum_p\)表示\(p\)出现的次数
恼了不想打高精
顺便放道题
这题首先明显是组合数,先枚举\(0\le i\le n\)
然后可以发现一定会有\((i-1)*k\)只牝牛
枚举牝牛的位置,只能在\(n-(i-1)\times k\)位置上选
方案数就是\(\dbinom{i}{n-(i-1)\times k}\)
然后就直接卢卡斯定理就能过了
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int s = 0,w = 1;char ch = getchar();
while(ch<'0'||ch>'9'){ if(ch == '-') w = -1;ch = getchar();}
while(ch>='0'&&ch<='9'){ s = s*10+ch-'0';ch = getchar();}
return s*w;
}
inline int qpow(int a,int k,int p){
int res=1;
while(k){
if(k&1) res=res*a%p;
k>>=1;
a=a*a%p;
}
return res;
}
inline int Comb(int a,int b,int p){
if(a<b) return 0;
int res=1;
for(int i=1,j=a;i<=b;i++,j--)
res=res*j%p,
res=res*qpow(i,p-2,p)%p;
return res;
}
inline int lucas(int a,int b,int p){
if(a<p&&b<p) return Comb(a,b,p);
return Comb(a%p,b%p,p)*lucas(a/p,b/p,p)%p;
}
signed main(){
int a=read(),b=read(),p=5000011,ans=0;
for(int i=0;i<=a;i++){
int j=a-(i-1)*b;
if(j<i)break;
ans=(ans+lucas(j,i,p))%p;
}
cout<<ans<<endl;
}