我觉得超详细了???
题解:
我们先来考虑一下什么情况下,答案会为0。
(1),你都比m大了还加个鬼啊
(2),因为包含
的区间的起点最多只能包含
各一次
(3),因为包含
的区间结束位置最多只能为
各一次。
(4),因为包含
的区间若有
个,必然至少有
个区间包含
,包含
的区间同理
--
除了以上4种情况外,接下来来解决其他情况。
直接上。
表示前
个数加到
的方案数,但这里需要修改一下区间加的合法性,把原先的对于任意两次区间加的起始,结束位置各不相同修改为对于任意区间的起始位置各不相同,除了以i结尾外,结束位置各不相同换句话说,就是允许多个以
结尾的区间。显然遍历到
时,以
结尾的区间有
个,如果我们先判断一下若
则原题的答案变为0了,那么遍历到
时,则我们修改的条件同时满足了原先的条件。那么答案便是
了。
现在考虑状态转移:
(1)当时,
,即把原先以
结尾的区间都延迟到
或新设区间
和从原先
个以
结尾的区间选
个出来延迟到
。
(2)当时,
,因为此时包含
的区间比包含
的区间多了一个,所以不能新设区间
而要从原先的以
结尾的区间选出来延长。
(3)当时,
这个时候,以
结尾的区间就都要延长啦。
至此结束,时间复杂度
代码:
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int MX=3e5+7;
const int mod=998244355;
using namespace std;
ll qpow(ll a,ll b,ll MOD=mod){for(ll ans=1;;a=a*a%MOD,b>>=1){if(b&1)ans=ans*a%MOD;if(!b)return ans;}}
ll inv(ll a,ll MOD=mod){return qpow(a,MOD-2,MOD);}
ll __gcm(ll a,ll b){return a*b/__gcd(a,b);}
ll dp[MX];
int a[MX];
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
ll ans=1;
dp[1]=1;
if(m-a[1]>1||a[1]>m){
cout<<0<<endl;
return 0;
}
for(int i=2;i<=n;i++)
{
if(m-a[i]>i||m<a[i]||(m-a[i]>(n-i+1)))
{
cout<<0<<endl;
return 0;
}
if(a[i-1]-a[i]==1)
{
dp[i]=dp[i-1];
}
else if(a[i]-a[i-1]==1)
{
dp[i]=dp[i-1]*(m-a[i-1])%mod;
}
else if(a[i]==a[i-1])
{
dp[i]=(dp[i-1]+dp[i-1]*(m-a[i-1]))%mod;
}
else {
cout<<0<<endl;
return 0;
}
// cout<<dp[i]<<endl;
}
cout<<dp[n]<<endl;
}



京公网安备 11010502036488号