马老师打算起飞。
一个长度为 2 n ( 2n\ ( 2n (可能有前缀 0 ) 0) 0) 的非负整数 x x x 是 g o o d good good 的,当且仅当存在两个长度为 n ( n\ ( n (可能有前缀 0 ) 0) 0) 的非负整数 a 、 b a、b a、b 满足 a + b = 1 0 n a+ b =10 ^ n a+b=10n,并且对于 0 ∼ 9 0\sim9 0∼9 每个数位 d d d,都有 S d ( x ) = S d ( a ) + S d ( b ) ( S d ( x ) Sd(x) = Sd(a) + Sd(b)(Sd(x) Sd(x)=Sd(a)+Sd(b)(Sd(x)为 x x x 的十进制中 d d d 出现了多少次 ) ) )。例如 0829 0829 0829 是 g o o d good good 的, 98 + 02 = 100 98 + 02 = 100 98+02=100 。
给出一个长度为 2 n 2n 2n 的序列,其中有些位置是问号。将每个问好替换为 0 ∼ 9 0 \sim 9 0∼9 任意一个数位后,有多少个 g o o d good good 数,答案对 1000000007 1000000007 1000000007 取模。
一行长度为 2 n 2n 2n 的字符串,由 0 ∼ 9 0 \sim 9 0∼9 和 ? ? ? 构成。
一个整数表示答案。
样例输入
2?4?
样例输出
4
设 m m m 为 ? ? ? 的个数。
对于 30 % 30\% 30% 的数据, n ≤ 6 n \leq 6 n≤6 。
对于另外 30 % 30\% 30% 的数据, m ≤ 6 m \leq 6 m≤6 。
对于 100 % 100\% 100% 的数据, n ≤ 50000 , m ≤ 1000 n \leq 50000,m \leq 1000 n≤50000,m≤1000 。
题解:
注意到,设 a a a 的十进制为 a 1 a 2 a 3 … a n a_1a_2a_3\dots a_n a1a2a3…an , b b b 为 b 1 b 2 b 3 … b n b_1b_2b_3\dots b_n b1b2b3…bn,那么必定是 a 1 + b 1 = 9 a_1+b_1=9 a1+b1=9, a 2 + b 2 = 9 a_2+b_2=9 a2+b2=9, a k + b k = 10 a_k+b_k=10 ak+bk=10, a k + 1 + b k + 1 = 0 … a n + b n = 0 a_{k+1}+b_{k+1}=0\dots a_n+b_n=0 ak+1+bk+1=0…an+bn=0。
于是考虑枚举 a k , b k a_k,b_k ak,bk,然后贪心先配已知的和为十,然后枚举和为十的数对 D P DP DP。
注意考虑 0 + 9 0+9 0+9和 0 + 0 0+0 0+0,当剩余的数个数是奇数时,多的位可以填 0 0 0 或 9 9 9 ,但填 9 9 9 时不能有 0 + 0 0+0 0+0 出现,因为会算重。
#include<bits/stdc++.h>
#define N 50005
#define M 1005
using namespace std;
const int mod=1000000007;
int read(){
int op=1,sum=0;char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') op=-1;ch=getchar();}
while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar();
return op*sum;
}
int jc[N],jcinv[N];
inline int power(int x,int c){
int now=1;
while(c){
if(c&1)now=1ll*now*x%mod;
x=1ll*x*x%mod;c>>=1;
}
return now;
}
inline void init(int n){
jc[0]=1;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%mod;
jcinv[n]=power(jc[n],mod-2);
for(int i=n-1;i+1;--i)jcinv[i]=1ll*jcinv[i+1]*(i+1)%mod;
}
inline int C(int x,int y){
if(x<y||y<0)return 0;
return 1ll*jc[x]*jcinv[y]%mod*jcinv[x-y]%mod;
}
char s[N<<1];
int cnt[11],res,pre[11],cal[11],f[M],g[M],tmp[M];
int dx[]={
1,2,3,4};
int dy[]={
8,7,6,5};
int main(){
// freopen("data.in","r",stdin);
// freopen("eatbuff.in","r",stdin);
// freopen("eatbuff.out","w",stdout);
init(M-2);
scanf("%s",1+s);
int n=strlen(1+s);
for(int i=1;i<=n;++i){
if(s[i]=='?'){
++res;continue;}
pre[s[i]-'0']++;
}
int ans=0,num=res;
for(int t=1;t<=5;++t){
res=num;
memset(cal,0,sizeof(cal));
for(int j=0;j<10;++j)cnt[j]=pre[j];
cnt[t]--,cnt[10-t]--;
if(cnt[t]<0){
cal[t]++;cnt[t]++;res--;
}
if(cnt[10-t]<0){
cal[10-t]++;cnt[10-t]++;res--;
}
for(int j=0;j<=4;++j){
int now=min(cnt[j],cnt[9-j]);
cnt[j]-=now,cnt[9-j]-=now;
}
for(int j=1;j<=9;++j){
if(cnt[j]){
cal[9-j]+=cnt[j],res-=cnt[j];
}
}
if(res<0)continue;
memset(tmp,0,sizeof(tmp));
if(res&1){
res>>=1;
cal[0]++;
for(int i=0;i<=res;++i){
//0 0
for(int j=0;j+i<=res;++j){
//0 9
tmp[i+j]=(tmp[i+j]+1ll*jcinv[cal[0]+2*i+j]*jcinv[cal[9]+j]%mod)%mod;
}
}
cal[0]--;
cal[9]++;
for(int j=0;j<=res;++j){
tmp[j]=(tmp[j]+1ll*jcinv[cal[0]+j]*jcinv[cal[9]+j]%mod)%mod;
}
cal[9]--;
res=(res<<1)|1;
}else{
res>>=1;
for(int i=0;i<=res;++i){
//0 0
for(int j=0;j+i<=res;++j){
//0 9
tmp[i+j]=(tmp[i+j]+1ll*jcinv[cal[0]+2*i+j]*jcinv[cal[9]+j]%mod)%mod;
}
}
res<<=1;
}
if(res&1)cal[9]++,cnt[0]--;
res>>=1;
for(int i=1;2*i<=cnt[0];++i){
// 9 9
for(int j=0;j+i<=res;++j){
// 0 9
tmp[i+j]=(tmp[i+j]+1ll*jcinv[cal[0]+j]*jcinv[cal[9]+2*i+j]%mod)%mod;
}
}
memset(f,0,sizeof(f));
f[0]=1;
for(int t=0;t<4;++t){
memset(g,0,sizeof(g));
for(int i=0;i<=res;++i){
for(int j=0;j<=i;++j){
g[i]=(g[i]+1ll*f[j]*jcinv[cal[dx[t]]+i-j]%mod*jcinv[cal[dy[t]]+i-j]%mod)%mod;
}
}
for(int i=0;i<=res;++i){
f[i]=g[i];
}
}
int pre=ans;
for(int i=0;i<=res;++i){
ans=(ans+1ll*f[i]*tmp[res-i]%mod)%mod;
}
}
ans=1ll*ans*jc[num]%mod;
printf("%d\n",(ans+mod)%mod);
return 0;
}