2019ICPC南昌区域赛C题 And and Pair(数位dp)

这道题的数位dp是二维的,我们可以把这个问题抽象成在0-S中满足题目条件的两个数的个数,因此可以进行二维的数位dp,从这题我们发现无需记录前缀状态

只需考虑两个flag看是否大于原数,并且两个数不能都是1,而且当i是1,n不能是0.

最后算出的答案并不是全部答案,因为还有i<=j的情况,我们知道这两个肯定是对称的,但是i==j是有一个成立的,所以我们+1再除2就行

除2的时候要小心,因为模数中的除法有点不同,所以要用逆元变成乘法

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
ll f[N][2][2];
string s;
string t;
int len;
ll qmi(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll dfs(int cur,int p1,int p2){
    if(cur==len){
        return 1;
    }

    auto &x=f[cur][p1][p2];
    if(x!=-1)
        return x;
    int v1=1,v2=1;
    if(p1){
        v1=s[cur]-'0';
    }
    if(p2)
        v2=s[cur]-'0';
    int i,j;
    ll ans=0;
    for(i=0;i<=v1;i++){
        for(j=0;j<=v2;j++){
            if(i==1&&j==1||(i&&s[cur]-'0'==0))
            continue;
            ans=(ans+dfs(cur+1,p1&&(i==v1),p2&&(j==v2)))%mod;
        }
    }
    return x=ans;
}
ll solve(string t){
    s=t;
    len=(int)s.size();
    return dfs(0,1,1);
}
int main(){
    int q;
    cin>>q;
    ll inv=qmi(2,mod-2);
    while(q--){
        memset(f,-1,sizeof f);
        cin>>t;
        printf("%lld\n",(solve(t)+1)*inv%mod);
    }
}
View Code

 

posted @ 2020-04-21 08:32  朝暮不思  阅读(580)  评论(0编辑  收藏  举报