ARC058C题解
观察到数据范围\(x+y+z\le 17\),正向计算不好算,考虑反向计算,计算出不会满足题目条件的数量,考虑dp,对于每一个位置而言都有可能是构成题意的,那么就一定意味着它的某些后缀和满足了题意,而结合上文的数据范围,我们可以从对后缀和进行状压的角度出发,如果从右向左数第\((k-1)\)位为\(1\),那么就意味着后缀和当中存在着\(k\)这个数。枚举从\(1\)到\(10\)的每个数\(Number\),因为加上了这个数字,相当于原有的后缀和每个都加上了这个数字,即原有的\(mask\)每个都向左移动了\(Number\)位,同时在第\((Number-1)\)位或上了\(1\),那么这个时候出现了一个问题就是后缀和\(> (x+y+z)\)的情况应该怎么处理,这些状态不需要被考虑到,因为这些后缀和不存在满足题意的情况。最后我们还需要检查一下是否会出现满足题意的情况,即\(CurMask>>(z-1)\&1=1,CurMask>>(y+z-1)\&1=1,CurMask>>(x+y+z-1)\&1=1\)。时间复杂度为\(O(10n2^{x+y+z})\)
代码
#include <bits/stdc++.h>
using namespace std;
/*
/\_/\
( =o.o= ) *
/ > \>
*/
#define ll long long
#define i128 __int128_t
#define ld long double
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define ull unsigned long long
#define VI vector<int>
#define VII vector<VI>
#define VL vector<ll>
#define VLL vector<VL>
ll x,y,z,n;
const int N=1500000;
const ll mod=1e9+7;
ll f[42][N];
ll ksm(ll a,ll b){
ll res=1;
while(b){
if(b&1){
res=res*a%mod;
}
b>>=1,a=a*a%mod;
}
return res;
}
bool check(ll mask,ll bit){
return (mask>>(bit-1))&1;
}
void sol() {
cin>>n>>x>>y>>z;
f[0][0]=1;
ll Lim=(1ll<<(x+y+z))-1;
for(int i=1;i<=n;i++){
for(ll Number=1;Number<=10;Number++){
for(ll mask=0;mask<=Lim;mask++){
ll CurMask=((mask<<Number)|(1ll<<(Number-1)))&Lim;
if(check(CurMask,z)&&check(CurMask,y+z)&&check(CurMask,x+y+z)) continue;
else{
f[i][CurMask]=(f[i][CurMask]+f[i-1][mask])%mod;
}
}
}
}
ll sum=0;
for(ll mask=0;mask<=Lim;mask++){
sum=(sum+f[n][mask])%mod;
}
cout<<(ksm(10,n)-sum+mod)%mod<<'\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--) {
sol();
}
return 0;
}

浙公网安备 33010602011771号