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;
}
posted @ 2026-05-25 19:54  1445141  阅读(8)  评论(0)    收藏  举报