주제 링크 : 포인트 I 아 ╭ (╯ ^ ╰) ╮
효과에 따라 :
길이
숫자의 위치는 일부
,
그것은 할 수있다
~
이 숫자로 나눌 필요
,
시간은 물어
항상 먼저 물어
작은 솔루션
문제 해결 아이디어 :
용
에서 분할
그런 생각
이 프로그램은,
프로그램의 물음표 번호
로서
, 만약
균일 한 분포의 개수 나누어
대한 개수
그러므로
이고 그 후, 탐색 할 수있다
물음표 방식의 전술 물음표로 촬영
에 최초로
물음표, 다이
이다
프로그램 번호
참고
시간, 당신은 초기에 미치는 영향에 추가 할,
초기의 영향을 해결하기 위해 제 아니더라도 높은 함께 가장 욕심으로 이해 될 수있는
초기 영향도 고려하면서 제 하이에서 로우로 질의를 열거 시간
시간 복잡성 :
코어 : DP + 생각
#include<bits/stdc++.h>
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 5;
const ll mod = 1e9 + 7;
int T, n, m, q;
char s[maxn];
ll dp[30][30], fac1[50], fac2[50];
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d%d%d%s", &n, &m, &q, s);
ll p1 = 1, p2 = 1, val = 0, rem = 0, cnt = 0, k;
for(int i=n-1; ~i; i--) {
if(isdigit(s[i])) {
val = (val + (s[i]-'0') * p1 % mod) % mod;
rem = (rem + (s[i]-'0') * p2 % m) % m;
} else if(cnt < 20) {
fac1[++cnt] = p1;
fac2[cnt] = p2;
}
p1 = p1 * 10 % mod;
p2 = p2 * 10 % m;
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i=1; i<=cnt; i++)
for(int j=0; j<m; j++)
for(int x=0; x<10; x++) {
if(i > 1) dp[i][j] += dp[i-1][(j + fac2[i] * x % m) % m];
else dp[i][j] += dp[i-1][(j + rem + fac2[i] * x % m) % m];
if(dp[i][j] >= 1e18 + 10 || dp[i][j] < 0) dp[i][j] = 1e18 + 10;
}
while(q--) {
scanf("%lld", &k);
if(dp[cnt][0] < k) {
puts("-1");
continue;
}
ll ans = val, pre_rem = 0, now_rem;
for(int i=cnt; i; i--)
for(int x=0; x<10; x++) {
if(i > 1) now_rem = (pre_rem + fac2[i] * x % m) % m;
else now_rem = (pre_rem + rem + fac2[i] * x % m) % m;
if(dp[i-1][now_rem] < k) k -= dp[i-1][now_rem];
else {
pre_rem = now_rem;
ans = (ans + fac1[i] * x % mod) % mod;
break;
}
}
printf("%lld\n", ans);
}
}
}