三只数学题

1.分特产

首先考虑分设 \(f_i\)\(g_i\) 分别表示钦定与恰好,由题意我们容易知道 \(f_i\) 首先应钦定 \(i\) 个人,方案为 \(\binom{n}{i}\),然后对剩下的 \(n-i\) 个人插 \(a_j\) 个板,有 \(\binom{a_j+n-i-1}{a_j}\) 种方案数,因此有 $$f_i=\binom{n}{i}+\prod_{j=1}^n\binom{a_j+n-i-1}{a_j}$$然后我们只需要根据二项式反演推出 \(g_i\) 来即可。

点击查看代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int n,m,ans(0);
int a[100000],fac[500000],F[2000],G[2000];
int qpow(int a,int b){
	int res(1);
	for(;b;a=(a*a)%p,b>>=1) if(b&1) res=(res*a)%p;
	return res%p;
}
// int cc(int n,int m){return (m>n)?0:fac[n]*qpow(fac[n-m],p-2)%p*qpow(fac[m],p-2)%p;}
// int C(int n,int m){return !m?1:cc(n%p,m%p)%p*C(n/p,m/p)%p;}

int cc(int n,int m){return (m>n)?0:((fac[n]*qpow(fac[m],p-2))%p*qpow(fac[n-m],p-2)%p);}
int C(int n,int m){return !m?1:cc(n%p,m%p)*C(n/p,m/p)%p;}
signed main(){
	fac[0]=1;
	for(int i=1;i<=350000;++i) fac[i]=fac[i-1]*i%p;
	scanf("%lld %lld",&n,&m);
	for(int i=1;i<=m;++i) scanf("%lld",&a[i]);
	int tem(1);
	for(int i=0;i<n;++i){
		tem=1;
		for(int j=1;j<=m;++j) tem=tem*C(a[j]+n-i-1,n-i-1)%p;
		F[i]=C(n,i)*tem%p;
	}
	for(int i=0;i<n;++i){
		if(i&1) ans=(ans-F[i])%p;
		else ans=(ans+F[i])%p;
	}
	printf("%lld",ans);
}

2. 工业题:

题目描述:给出函数 \(f_{i,j}\) 有如下递推式:

\[f_{i,j}=f_{i,j-1}\times a+f_{i-1,j}\times b \]

其中 \(a\)\(b\) \(f_{i,0}\) 以及 \(f_{0,i}\) 给出,求出 \(f_{i,j}\)

首先暴力递推不用说,我们考虑 \(f_{i,j}\) 能以何种方式贡献给 \(f_{n,m}\),而二者的曼哈顿距离是一定的,这也就意味这 \(f_{i,j}\) 一定会经过 \(n-i\) 次与 \(a\) 相乘,也就是 \(a^{n-i}\),同理有 \(b^{m-j}\)。而所有走法都能给 \(f_{i,j}\) 产生贡献。故有:

\[f_{n,m}=\sum f_{i,j}\times 方案数\times a^{n-i}\times b^{m-j} \]

接下来考虑方案数,感觉这个方案数挺有用的,以后记下来,它是:\(n+m-i-j\choose n-i\)。然后这题就完事儿了。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+10,p=998244353;
int n,m,a,b,ans(0);
int f[N],g[N];
int qpow(int a,int b){
    int res(1);
    for(;b;a=(a*a)%p,b>>=1) if(b&1) res=(res*a)%p;
    return res%p;
}
int fac[N],ifac[N];
int C(int n,int m){return fac[n]*ifac[n-m]%p*ifac[m]%p;}
signed main(){
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    scanf("%lld %lld",&n,&m);
    scanf("%lld %lld",&a,&b);
    a%=p,b%=p;
    for(int i=1;i<=n;++i) scanf("%lld",&f[i]),f[i]%=p;
    for(int i=1;i<=m;++i) scanf("%lld",&g[i]),g[i]%=p;
    fac[0]=1;ifac[0]=1;
	for(int i=1;i<=n+m;++i) fac[i]=fac[i-1]*i%p;
	ifac[n+m]=qpow(fac[n+m],p-2);
	for(int i=n+m-1;i>=1;--i) ifac[i]=ifac[i+1]*(i+1)%p;
    for(int i=1;i<=m;++i){
        ans=(ans+C(n+m-i-1,n-1)%p*g[i]%p*qpow(a,m-i)%p*qpow(b,n))%p;
        ans%=p;
    }
    for(int i=1;i<=n;++i){
        ans=(ans+C(n+m-i-1,m-1)%p*f[i]%p*qpow(a,m)%p*qpow(b,n-i))%p;
        ans%=p;
    }
    printf("%lld",ans%p);
}

\(P.S.\) 关于那个组合数,就是把矩形的下(或右)确定了,另一个方向也就随之确定,因此总组合数中选向下(或右)的方案即可。

玄学题:

给定:

\[\sum_{i=1}^n(-1)^{\sum_{j=1}^m d(i\times j)} \]

\(n\)\(m\) 给定,求其值。

好吧,被诈骗了,还以为是什么反演题,结果是要看奇偶性质。首先思考答案为 \(n\) 减去 \(-1\) 的贡献,那么思考 \(-1\) 的出现与什么有关,当 \(\sum_{j=1}^m d(i\times j)\) 为奇数时有贡献,因此思考 \(d(i\times j)\) 何时为奇数,只有当 \(i\times j\) 为完全平方数时有此种效果,也就是说,只有当 \(i\) 中的质因数 \(p\)\(j\) 中的质因数 \(p\) 是“成双成对” 的,这样的话,我们只需要预处理出每个 \(i\) 的贡献即可,即当奇数贡献出现了奇数次时,才会将答案减少 \(1\),反之增加 \(1\)。又因为满足条件的 \(j\) 可以写成是 \(p\times r^2\) 的形式,故对于每个 \(i\)\(\sqrt{{\frac{m}{p}}}\) 个贡献,奇偶判一下即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+10;
int fu[N];
signed main(){
	int n,m;cin>>n>>m;
	for(int i=1;i*i<=n;++i){
		for(int j=1;j*i*i<=n;++j){
			fu[i*i*j]=j;
		}
	}
	int ans(0);
	for(int i=1;i<=n;++i){
		if((int)sqrt(m/fu[i])&1) ans--;
		else ans++;
	} 
	cout<<ans;
}
posted @ 2023-08-08 06:40  Melting_Pot  阅读(35)  评论(0编辑  收藏  举报