题目:D 火柴排队
组合数需要求一下,顺便总结一下组合数求的几种方法。
C
n
m
=
C
n
−
1
m
+
C
n
−
1
m
−
1
C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1}
Cnm=Cn−1m+Cn−1m−1,概念展开证明。由于这里只需要求
C
n
k
C_n^{k}
Cnk线性推导也可以。
选择i个元素增加k,不改变排名,我们需要知道n个数选择1,2,3…个的时候不改变原始排名的数量。n的范围考虑dp,构造状态dp[i][j][2]:前i个人以i结尾选择了j个并且没有改变原始排名的方法数,第i个元素选没选,那么由dp[i-1][][]转移的条件就出来了。(也可以用滚动数组优化)
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
typedef double ld;
typedef pair<ll,ll> PP;
const ll mod=998244353;
ll a[5010];
ll C[5010];
ll inv[5010];
ll dp[5010][5010][2];
ll qpow(ll a,ll n) {
ll res=1;
while(n) {
if(n&1)
res=(res*a)%mod;
n>>=1;
a=(a*a)%mod;
}
return res;
}
void init(int n) {
C[0]=1;
for(int i=1;i<=n;++i) {
C[i]=(C[i-1]*(n-i+1))%mod;
ll temp=qpow(i,mod-2)%mod;
C[i]=(C[i]*temp)%mod;
}
for(int i=1;i<=n;++i) {
inv[i]=qpow(C[i],mod-2)%mod;
}
}
int main() {
ll n,d;
scanf("%lld %lld",&n,&d);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
a[n+1]=1e9+2;
init(n);
sort(a+1,a+1+n);
dp[1][0][0]=dp[1][1][1]=1;
for(int i=0;i<=n;++i)
dp[i][0][0]=1;
for(int i=2;i<=n;++i) {
for(int j=0;j<=i;++j) {
if(a[i-1]+d<=a[i])
dp[i][j][0]=(dp[i-1][j][0]+dp[i-1][j][1])%mod;
else
dp[i][j][0]=(dp[i-1][j][0])%mod;
dp[i][j][1]=(dp[i-1][j-1][0]+dp[i-1][j-1][1])%mod;
}
}
for(int i=1;i<=n;++i) {
printf("%lld\n",(dp[n][i][0]+dp[n][i][1])*inv[i]%mod);
}
return 0;
}
题目:F 解方程
这道题目不会推导直接来源于题解。https://ac.nowcoder.com/acm/discuss/blogs?tagId=138721
积性函数的卷积仍为积性函数,也可以自己手动证明一下约数k次幂和是个积性函数拆解一下就可以证明,并且积性函数都可以用线性筛求出。
I
d
k
I d_k
Idk单位函数,等于自己本身的值,需要熟悉一下常见的卷积公式。带入其中作替换。形式联想到莫比乌斯反演可以得到新式子。
f
(
i
)
n
q
\frac{f(i)}{n^q}
nqf(i)由等式右边积性的证明,直接由其性质从质数切入。我们最后作一下变换,
f
(
i
)
=
d
q
−
d
p
d
q
∗
n
q
,
d
∣
n
,
d
∈
p
r
i
m
e
f(i)=\frac{d^q-d^p}{d^q}*n^q,d|n , d \in{prime}
f(i)=dqdq−dp∗nq,d∣n,d∈prime,可以发现分母和
n
q
n^q
nq的关系,相当于模拟了一遍欧拉筛。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PP;
typedef double ld;
const ll mod=998244353;
const int MAX=1e7+10;
int tot=0;
bool vis[MAX];
int prime[764679];
inline ll qpow(ll a,ll n) {
ll res=1;
while(n) {
if(n&1)
res=(res*a)%mod;
n>>=1;
a=(a*a)%mod;
}
return res%mod;
}
ll n,q,p;
ll f[MAX],g[MAX];
void init() {
memset(vis,false,sizeof(vis));
f[1]=1;
vis[1]=vis[0]=true;
for(int i=2;i<MAX;i++) {
if(!vis[i]) {
prime[tot++]=i;
g[i]=qpow(i,q);f[i]=(g[i]-qpow(i,p))%mod;
}
for(int j=0;j<tot;j++) {
if(i*prime[j]>=MAX)
break;
vis[prime[j]*i]=true;
if(i%prime[j]==0) {
f[prime[j]*i]=f[i]*g[prime[j]]%mod;
break;
}
f[prime[j]*i]=f[i]*f[prime[j]]%mod;
}
}
}
int main() {
scanf("%lld %lld %lld",&n,&p,&q);
init();
ll ans=0;
for(int i=1;i<=n;++i) {
f[i]=(f[i]%mod+mod)%mod;
ans^=f[i];
}
printf("%lld",ans);
return 0;
}