AtCoder Beginner Contest 167 比赛人数11940 比赛开始后15分钟看到A题,之后每隔一分钟,看到一道题,在比赛开始后第21分钟看到所有题
AtCoder Beginner Contest 167 E Colorful Blocks 快速幂+阶乘逆元+组合数计算+隔板法
总目录详见https://blog.csdn.net/mrcrack/article/details/104454762
在线测评地址https://atcoder.jp/contests/abc167/tasks/abc167_e
OOOOO
0个相邻的块同色的情况如下
O|O|O|O|O 4个位置插入4个隔板,C(n-1,4)
只有1个相邻的块同色的情况如下
O|O|O|OO 4个位置插入3个隔板,C(n-1,3)
只有2个相邻的块同色的情况如下
O|O|OOO 4个位置插入2个隔板,C(n-1,2)
只有3个相邻的块同色的情况如下
O|OOOO 4个位置插入1个隔板,C(n-1,1)
只有4个相邻的块同色的情况如下
OOOOO 4个位置插入0个隔板,C(n-1,0)
样例模拟如下
3 2 1
2
3 2 1
6
3 2 2
8
8种组合如下
111
112
121
122
211
212
221
222
0个相邻的块同色的情况如下(2个间隔,插入2个隔板)
121
212
计算如下:
位置 1 2 3
可选择颜色数量 2 1 1 根据乘法原理,种类是2*1*1=2
解释如下:
位置1有2种颜色可选,
位置2与位置1不同色,故有2-1=1种颜色可选
位置3与位置2不同色,故有2-1=1种颜色可选
根据乘法原理,种类是2*1*1=2
写成公式如下:
位置1有m种颜色可选,
位置2与位置1不同色,故有m-1=m-1种颜色可选
位置3与位置2不同色,故有m-1=m-1种颜色可选
根据乘法原理,种类是
C(n-1,n-1)*m*(m-1)*(m-1)=C((n-1,n-1)*m*(m-1)^2=C((n-1,n-1)*m*(m-1)^(n-1)
只有2个相邻的块同色的情况如下(2个间隔,插入1个隔板)
112
122
221
222
计算如下:
位置 1 2 3
可选位置1,2为同色块,或者位置2,3为同色块,有2种选择
每个相邻同色块颜色有2种选择
剩下的另一个位置,因与同色块颜色不同,有2-1=1种选择
根据乘法原理,种类是2*2*1=4
总的总类是C(n-1,n-1-1)*m*(m-1)^(n-1-1)
3个相邻同色的情况如下(2个间隔,插入0个隔板)
111
222
计算如下:
位置 1 2 3
可选位置1,2,3为同色块,有1种选择
每个相邻同色块颜色有2种选择
根据乘法原理,种类是1*2=2
总的总类是C(n-1,n-1-2)*m*(m-1)^(n-1-2)
明白手工计算过程后,如何编写,就看个人了。
AC代码如下
#include
#include
#define mod 998244353
#define maxn 200010
#define LL long long
using namespace std;
LL fact[maxn],inv[maxn],ans,t[maxn],p;
int n,m,k,nm;
LL quick_pow(LL a,LL b){//a^b
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
void init(){
int i;
scanf("%d%d%d",&n,&m,&k);
nm=n,nm=max(nm,m),fact[0]=1;
for(i=1;i<=nm;i++)fact[i]=fact[i-1]*i%mod;//fact[i]代表i!
inv[nm]=quick_pow(fact[nm],mod-2);
for(i=nm-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;//inv[i]代表i!的乘法逆元
}
LL C(LL a,LL b){//组合数计算
return fact[a]*inv[a-b]%mod*inv[b]%mod;
}
int main(){
int i;
init();
ans=0,p=quick_pow(m-1,n-k-1);
for(i=n-k;i<=n;i++){
ans=(ans+m*p%mod*C(n-1,i-1)%mod)%mod;//C(n-1,i-1)隔板法
p=p*(m-1)%mod;
}
printf("%lld\n",ans);
return 0;
}
类似的题目
洛谷 P3197 [HNOI2008]越狱