HDU 다중 학교 여섯 번째 1011 11 치수 - DP + 생각

주제 링크 : 포인트 I 아 ╭ (╯ ^ ╰) ╮

효과에 따라 :

    길이 숫자의 위치는 일부 ? ? , ? ? 그것은 할 수있다 0 0 ~ 9 9
    이 숫자로 나눌 필요 미디엄 미디엄 , 시간은 물어
    항상 먼저 물어 케이 케이 작은 솔루션

문제 해결 아이디어 :

    용 (23) ? ? (56) ? ? 23 ?? 56 ??
    에서 분할 23005600 23005600 + + ? ? 00 ? ? ?? 00 ??
    그런 생각 ? 이 프로그램은, c n t CNT 프로그램의 물음표 번호 1 0 c n t ^ {10} CNT
    로서 k 1 0 18 k≤10 ^ {18} , 만약 1 0 c n t ^ {10} CNT 균일 한 분포의 개수 나누어 m 미디엄 대한 개수 1 0 c n t m \ FRAC ^ {10} {CNT} {m}
    그러므로 c n t = 20 CNT = 20 이고 그 후, 탐색 할 수있다 20 (20) 물음표 방식의 전술 물음표로 촬영 0 0


     d p [ i ] [ j ] DP [I] [J] 에 최초로 i 나는 물음표, 다이 m 미디엄 이다 j 제이 프로그램 번호
     d p [ i ] [ j ] = d p [ i 1 ] [ j + 1 0 i × x ] DP [I] [J] = \ 합 DP [I-1] [J + 10 ^ I \ 시간 X]    x [ 0 , 9 ] X ∈ [0,9]
    참고 i = 1 I = 1 인 시간, 당신은 초기에 미치는 영향에 추가 할, 23005600 23005600
    초기의 영향을 해결하기 위해 제 아니더라도 높은 함께 가장 욕심으로 이해 될 수있는
    초기 영향도 고려하면서 제 하이에서 로우로 질의를 열거 시간
    시간 복잡성 : O ( 20 m 10 + q 20 10 ) O (20 * m * Q + 10 * 20 * 10)

코어 : 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);
		}
	}
}
게시 된 221 개 원래 기사 · 원 찬양 (220) ·은 20000 +를 볼

추천

출처blog.csdn.net/Scar_Halo/article/details/103102386