DP+组合数学典题

https://codeforces.com/contest/2041/problem/H

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define int long long
#define endl '\n'
const int N=1e6+10,mod=998244353;

typedef pair<int,int> PII;

int fact[N],infact[N];

int qmi(int a,int k){
	int res=1;
	while(k){
		if(k&1) res=res*a%mod;
		a=a*a%mod;
		k>>=1;
	}
	return res;
}

void init(){
	fact[0]=infact[0]=1;
	for(int i=1;i<N;i++) fact[i]=fact[i-1]*i%mod;
	infact[N-1]=qmi(fact[N-1],mod-2);
	for(int i=N-2;i>=1;i--) infact[i]=infact[i+1]*(i+1)%mod;
}

int C(int n,int m){
	return fact[n]*infact[n-m]%mod*infact[m]%mod;
}

int f[N][2],sum[N][2];
/*
题意转换,相当于就是不能出现连续k个>或者<, =无关答案,所以我们可以枚举>和<的数量即可
f[i][1]:表示选i个符号,不考虑=,并且第i个符号结尾是1的方案数
f[i][0]:第i个符号结尾是0
转移:
枚举f[i][1]中1的连续出现的次数,不大于等于k次就行
f[i][1]=sum(f[j][0]),其中i-j<k,前缀和优化即可

然后再逐个考虑加上=之后的方案数数量即可 
*/

void slove(){
	int n,k;
	cin>>n>>k;
	if(k==1){
		cout<<1<<endl;
		return ;
	}
	n--;
	f[1][1]=f[1][0]=sum[1][0]=sum[1][1]=1;
	int ans=(C(n,1)*2%mod+1)%mod;
	for(int i=2;i<=n;i++){
		f[i][1]=(sum[i-1][0]-sum[max(i-k,0ll)][0]+mod)%mod;
		f[i][0]=(sum[i-1][1]-sum[max(i-k,0ll)][1]+mod)%mod;
		if(i<k) f[i][1]++,f[i][0]++;
		sum[i][1]=(sum[i-1][1]+f[i][1])%mod;
		sum[i][0]=(sum[i-1][0]+f[i][0])%mod;
		ans+=(f[i][1]+f[i][0])%mod*C(n,i)%mod;
		ans%=mod;
	}
	cout<<(ans+mod)%mod<<endl;
}

signed main(){
//	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	init();
	int T=1;
//	cin>>T;
	while(T--) slove();
}
posted @   MENDAXZ  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示