emm,这题和数位dp关系不大
但是思维,代码能力需要比较厉害
注意到数据非常大,所以数位dp的O(n)查询不可取
但 是 x 个 问 号 可 以 组 成 1 0 x 个 数 但是x个问号可以组成10^x个数 但是x个问号可以组成10x个数
所 以 高 位 的 ? 大 部 分 都 应 该 是 0 所以高位的?大部分都应该是0 所以高位的?大部分都应该是0
直 接 d p 后 30 个 问 号 即 可 , 这 样 前 面 问 号 都 填 0 , 有 1 0 30 个 数 字 直接dp后30个问号即可,这样前面问号都填0,有10^{30}个数字 直接dp后30个问号即可,这样前面问号都填0,有1030个数字
这 些 组 成 方 案 中 , 肯 定 超 过 了 k 个 数 满 足 条 件 这些组成方案中,肯定超过了k个数满足条件 这些组成方案中,肯定超过了k个数满足条件
至 于 d p , 也 很 巧 妙 , 2 ? 3 ? ? 拆 分 为 20300 和 0 ? 0 ? ? 至于dp,也很巧妙,2?3??拆分为20300和0?0?? 至于dp,也很巧妙,2?3??拆分为20300和0?0??
这 样 可 以 直 接 d p 问 号 了 这样可以直接dp问号了 这样可以直接dp问号了
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=50009;
const int mod=1e9+7;
int quick_pow( int a,int b,int mo )
{
  int ans=1;
  while( b )
  {
    if( b&1 ) ans=ans*a%mo;
    a=a*a%mo;
    b>>=1;
  } return ans;
}
int dp[maxn][22],pos[maxn],pm[maxn],pmod[maxn];
string res;
int n,m,q;
signed main()
{
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  int T; cin >> T;
  while( T-- )
  {
    cin >> n >> m >> q;
    cin >> res;
    int len=res.length(),cnt=0;
    int amod=0,am=0;
    for(int i=0;i<len;i++)
    {
      amod*=10,am*=10;
      if( res[i]!='?' )
      {
        amod+=res[i]-'0';
        am+=res[i]-'0';
      }
      amod%=mod,am%=m;
    }
    for(int i=len-1;i>=0;i--)
      if( res[i]=='?' ) pos[++cnt]=len-i-1;
    am=( m-am )%m;//还需要这么多
    for(int i=1;i<=cnt;i++)
    {
      pm[i]=quick_pow(10,pos[i],m);
      pmod[i]=quick_pow(10,pos[i],mod);
    }
    for(int i=0;i<=cnt;i++)
    for(int j=0;j<20;j++)
      dp[i][j]=0;
    dp[0][0]=1;
    for(int i=1;i<=cnt;i++)//后往前dp 
    for(int j=0;j<=9;j++)
    {
      int now=j*pm[i]%m;//尝试放数字j 
      for(int k=0;k<m;k++)
      {
        int ne=(now+k)%m;
        dp[i][ne]+=dp[i-1][k];
        dp[i][ne]=min( dp[i][ne],(int)1e18);
      }
    }
    while( q-- )
    {
      int ans=amod,k;
      cin >> k;
      if( dp[cnt][am]<k )
      {
        cout << -1 << '\n';
        continue; 
      } 
      int now=am;
      for(int i=min(cnt,(int)30);i>=1;i-- )
      for(int j=0;j<=9;j++)//当前位放j 
      {
        int ne=( (now-j*pm[i]%m )+m )%m;//上一个状态 
        if( dp[i-1][ne]<k ) k-=dp[i-1][ne];
        else
        {
          ans+=j*pmod[i]%mod;
          ans%=mod;
          now=ne;
          break;          
        }
      }
      cout << ans % mod << '\n';
    } 
  }
}









