题解:P11856 [CSP-J2022 山东] 吟诗
Blog
“存在妙手”这个限制不好计数,因为可能会重复计一个妙手,且总方案数与不含妙手的方案数统计是较为容易的,所以考虑容斥,统计不含妙手的方案数。
考虑怎么刻画“分段和”的限制,显然我们可以利用前缀和的思想,如果到了第
因为前缀和只能利用差值来设计 DP 方案,不太直观,所以考虑转化为后缀和设计 DP:
总方案数为
时间复杂度
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int ALL=(1<<18)-1;
const ll mod=998244353;
ll n,x,y,z,dp[50][300005],ban,ans=1;
int main()
{
//freopen("sample.in","r",stdin);
//freopen("sample.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>x>>y>>z;
ban=((1<<z)|(1<<(y+z))|(1<<(x+y+z)));
dp[0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=ALL;j++)
{
for(int v=1;v<=10;v++)
{
int st=(((j<<v)|(1ll<<v))&ALL);
if((st&ban)==ban)continue;
dp[i+1][st]=(dp[i+1][st]+dp[i][j])%mod;
}
}
ans=(ans*10)%mod;
}
for(int i=0;i<=ALL;i++)
ans=((ans-dp[n][i]+mod)%mod+mod)%mod;
cout<<ans;
return 0;
}