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); } }
没有人不辛苦,只有人不喊疼