qbxt五一数学Day3

1. 组合数取模

(nm)modp

1. n,m200p 任意

递推

2. n,m106p109 素数

预处理 n!m!1(nm)!1 即可 .

3. n,m106p2000 素数

注意到 n 可能是 p 的倍数,故逆元可能不存在 .

引入 Lucas 定理:

n,mpp 是质数)进制下表示为

nknk1nk2n1¯,mkmk1mk2m1¯

其中 0ni<p0mi<p .

则有:

(nm)(nkmk)(nk1mk1)(n1m1)(modp)

Proof:
原问题等价于 CmnCmmodpnmodpCm/pn/p(modp) .

xN+,且 x<p,则:

Cpx=p!x!(px)!=p(p1)!x(x1)!(px)!=pxCp1x1

由于 x<pp 是素数,所以 x 存在模 p 意义下的逆元,因此:

Cpxpx1Cp1x1(modp)

因为 px1Cp1x10(modp) ,故 Cpx0(modp).

由二项式定理,

(1+x)p=i=0pCpixi

除了 i=0,i=p 的项数,别的模 p 均为 0,所以:

(1+x)p1+xp(modp)

现在我们设:

{m/p=qmn/p=qn , {mmodp=rmnmodp=rn

从而:

{m=qmp+rmn=qnp+rn

再由二项式定理有

(1+x)m=i=0mCmixi

而同时又有:

(1+x)m=(1+x)qmp+rm=(1+x)qmp(q+x)rm=((1+x)q)mp(q+x)rm(1+xp)qm(1+x)rm=i=0qmCqmixipi=0rmCrmixi=i=0qmj=0rmCqmiCrmjxip+j(modp)

注意到 ip+j 正好能取到 0m 内所有整数一次,所以枚举 k=ip+j,得

(x+1)mk=0nCqmk/pCrmkmodpxk(modp)

结合二项式定理,得

k=0mCmkxkk=0nCqmk/pCrmkmodpxk(modp)

对比系数,得:

CmnCmmodpnmodpCm/pn/p=CqmqnCrmrn(modp)

命题获证 .

4. n,m106p=p1p2pkp1,p2,,pk2000 为互不相同的素数

A=(nm)

{A(nm)(modp1)A(nm)(modp2)A(nm)(modpk)

用 Lucas 定理求组合数,然后 CRT 合并即可

2. 抽屉原理,容斥原理

1. 抽屉原理

抽屉原理:

n+1 个物品放入 n 个抽屉,必有一抽屉至少有两个物品 .

2. 容斥原理

|i=1nAi|=B{A1,A2,,An}(1)|B|+1|AiBAi|

典型题:n 夫妻问题

n 对夫妻排成一圈,共 2n 人,夫妻不能相邻,求方案数 .

前置:圆排列

n 个人排成一圈,方案数为 (n1)!(旋转算一种)(所以去除 n

n 夫妻问题固定每个夫妻,用容斥原理:

i=0n(1)i(ni)(2ni1)!2i

小题

1. 组合数问题

请你把 n 拆成 k 个不同的组合数之和,输出任意一种方案

两个组合数 (n1m1),(n2m2) 不同当且仅当 n1n2m1m2

n109k103 .
乱构造

n=(00)+(10)+(20)++(k20)+(nk+11)

2. 组合数问题

k 个不同(不同的定义同上题)的组合数,求它们和的最大值 .

对于选取的组合数 (pq) 要求 0p,qn

n106k105 .

用一个堆维护最值,每次加入杨辉三角形中四周的组合数即可 .

比较两个组合数取对数即可 .

3. 组合数问题

i=0Cnkik+r

注意到对组合数作 k 次展开可以得到一个引理

Lemma

(nm)=i=0k(nkmi)(ki)

k 为任意整数

An,r=i=0Cnkik+r=i=0j=0kC(n1)kik+rjCkj=j=0ki=0C(n1)kik+rjCkj=j=0kCkji=0C(n1)kik+rj=j=0kCkjAn1,rj

然后矩阵快速幂优化,时间复杂度 O(k3logn) .

4. 万圣节

给定 n 个数,找若干个数使得它们是 c 的倍数 .

前缀和

5. 正方形

给定平面上 n 点,用三个 L×L 正方形覆盖所有点,求最小的 L .

二分 L,判定就是两个正方形都放在角上,剩下一个再判定

下午比赛

380 pts 混了个 rank1 .

T1

给定 x,y,求 xmody .

x10100000,y231

有手就行

T2

大小为 3×N 的方格图,你需要用有M种颜色的大小为 1×12×2 的小方块去覆盖整个方格图。小方块和小方块之间不能互相覆盖,并且必须将整个方格图全部覆盖。求有多少种覆盖方格图的方法。两种方案不一样当且仅当存在某个位置颜色不一样或者摆放小方块的方法不一样。
.

N,M109

推(?)个式子,然后矩乘优化

T3

xC(n,m)mod1000003471

1x,n,m105 .

欧拉降幂,对模数质因数分解,Lucas 定理求然后 CRT 合并

T4

给定 N 个数,其中第 i 个数为 gcd(x,y+i1) . 求任意一组可能的 x,y 的值 .

1N1000,保证存在答案 x,y109 .

考场上胡了个 O(y) 暴力,80pts .

显然 x=lcm(a1,a2,,aN) .

ai=gcd(x,y+i1) 列出同余方程,CRT 解出 y 即可 .

Code

T1

using namespace std;
typedef long long ll;
string str;
ll p,ans;
int main()
{
	cin>>str; int l=str.length();
	scanf("%lld",&p);
	for (int i=0;i<l;i++) ans=(ans*10+str[i]-'0')%p;
	printf("%lld\n",ans);
	return 0;
}

T2

using namespace std;
typedef long long ll;
const int MOD=1e9+7,N=5;
ll n,m;
ll qpow(ll x,ll n,ll p)
{
	ll ans=1;
	while (n)
	{
		if (n&1) ans=ans*x%p;
		n>>=1; x=x*x%p;
	} return ans;
}
struct mat
{
	ll a[N][N];
	mat operator *(const mat& mD)
	{
		mat ans; memset(ans.a,0,sizeof ans.a);
		for (int i=1;i<=2;i++)
			for (int k=1;k<=2;k++)
				for (int j=1;j<=2;j++)
					ans.a[i][j]=(ans.a[i][j]+mD.a[k][j]*a[i][k]%MOD)%MOD;
		return ans;
	}
	mat operator ^(int q)
	{
		mat ans,b=*this;
		ans.a[1][1]=(qpow(m,6,MOD)+2*qpow(m,3,MOD))%MOD; ans.a[1][2]=qpow(m,3,MOD);
		while (q)
		{
			if (q&1) ans=ans*b;
			b=b*b; q>>=1;
		} return ans;
	}
}B;
int main()
{
	scanf("%lld%lld",&n,&m);
	if (n==1){printf("%lld\n",qpow(m,3,MOD)); return 0;}
	if (n==2){printf("%lld\n",(qpow(m,6,MOD)+2*qpow(m,3,MOD))%MOD); return 0;}
	B.a[1][1]=qpow(m,3,MOD);   B.a[1][2]=1;
	B.a[2][1]=2*qpow(m,3,MOD); B.a[2][2]=0;
	printf("%lld",(B^(n-2)).a[1][1]%MOD);
	return 0;
}

T3

using namespace std;
typedef long long ll;
const int List[]={2,3,5,53,677,929},MOD=1000003471;
const int N=1e4+5;
ll C[N][N];
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
int Lucas(int n,int m,int p)
{
	for (int i=0;i<p;i++)
	{
		C[i][0]=1;
		for (int j=1;j<=i;j++)
		{
			C[i][j]=C[i-1][j-1]+C[i-1][j];
			if (C[i][j]>=p) C[i][j]-=p;
		}
	} // init
	int ans=1;
	while (n||m){ans=ans*C[n%p][m%p]; n/=p; m/=p;}
	return ans;
}
ll qpow(ll x,ll n,ll p)
{
	ll ans=1;
	while (n)
	{
		if (n&1) ans=ans*x%p;
		n>>=1; x=x*x%p;
	} return ans;
}
int x,n,m;
ll M=1000003470,ans=0;
int main()
{
	scanf("%d%d%d",&x,&n,&m);
	for (int i=0;i<6;i++)
	{
		ll Q=List[i],P=Lucas(n,m,Q);
		ans+=P*(M/Q)%M*qpow(M/Q,Q-2,Q)%M;
	} printf("%lld\n",qpow(x,ans,MOD)%MOD);
	return 0;
}

T4 80pts(应该没人想看这里)

using namespace std;
typedef long long ll;
const int MOD=1e9+7,N=2050;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll n,a[N],x=1;
int main()
{
	scanf("%lld",&n);
	for (int i=1;i<=n;i++) scanf("%lld",a+i),x=lcm(x,a[i]);
	for (ll D=a[1];D<=1e9;D+=a[1])
	{
		bool vis=true;
		if (D+n-1>1e9) continue;
		for (ll now=D+1;now<=D+n-1;now++)
			if (now%a[now-D+1]){vis=false; break;}
		if (vis){printf("%lld %lld\n",x,D); return 0;}
	} printf("stO zhx Orz");
	return 0;
}
// 4 3 2

T4

using namespace std;
typedef long long ll;
const int N=2050;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll n,a[N],p,q,x=1;
void merge(ll& a1,ll& m1,ll a2,ll m2)
{
	if (m2>m1) swap(m1,m2),swap(a1,a2);
	while (a1%m2!=a2) a1+=m1;
	m1=lcm(m1,m2);
}
int main()
{
	scanf("%lld",&n);
	for (int i=1;i<=n;i++) scanf("%lld",a+i),x=lcm(x,a[i]);
	p=0; q=1;
	for (int i=1;i<=n;i++)
	{
		int P=((1-i)%a[i]+a[i])%a[i],Q=a[i];
		merge(p,q,P,Q);
	} printf("%lld %lld",x,p);
	return 0;
}
posted @   yspm  阅读(107)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2020-05-03 浅谈前缀和
2020-05-03 浅谈 LCA
😅​
点击右上角即可分享
微信分享提示