1. 程式人生 > >清北學堂模擬賽d6t3 反擊數

清北學堂模擬賽d6t3 反擊數

kmp limit str sca mage images scanf 滿足 bool

技術分享

技術分享

分析:顯然是一道數位dp題,不過需要一些奇怪的姿勢.常規的數位dp能統計出一個區間內滿足條件的數的個數,可是我們要求第k個,怎麽辦呢?轉化為經典的二分問題,我們二分當前數的大小,看它是第幾大的,就可以了.

顯然數位dp套上模板,再用上kmp的next數組就可以了,傳遞4個參數:還剩下多少位沒有匹配,匹配了多少位,是否達到上限和是否匹配成功,到最後判斷一下就可以了.

學到了一種很強的思想:如果能求出i是第幾個數,要求出第k個數就可以二分i的值.

#include <cstdio>
#include <cstring>
#include <iostream>
#include 
<algorithm> using namespace std; long long L, R, K, f[20][2010][2]; int m, nextt[40], a[30]; char X[100]; void init() { nextt[0] = 0; nextt[1] = 0; for (int i = 1; i < m; i++) { int j = nextt[i]; while (j && X[i] != X[j]) j = nextt[j]; nextt[i
+ 1] = X[i] == X[j] ? j + 1 : 0; } } long long dfs(int len, int w, bool limit, bool flag) { if (len == 0) return flag; if (!limit && f[len][w][flag] != -1) return f[len][w][flag]; int maxn = limit ? a[len] : 9; long long cnt = 0; for (int i = 0; i <= maxn; i++) {
int t = w; while (t && X[t] - 0 != i) t = nextt[t]; if (X[t] - 0 == i) t++; cnt += dfs(len - 1, t, limit && (i == a[len]), flag || (t == m)); } return limit ? cnt : f[len][w][flag] = cnt; } long long query(long long u) { int cnt = 0; while (u) { a[++cnt] = u % 10; u /= 10; } memset(f, -1, sizeof(f)); return dfs(cnt, 0, 1, 0); } int main() { scanf("%lld %lld %s %lld", &L, &R, X, &K); m = strlen(X); init(); if (query(R) < K + query(L - 1)) { printf("Hey,wake up!\n"); return 0; } long long t = query(L - 1),ans = L; long long l = L, r = R; while (l < r) { long long mid = (l + r) >> 1; if (query(mid) - t >= K) { r = mid; ans = mid; } else l = mid + 1; } printf("%lld\n", r); return 0; }

清北學堂模擬賽d6t3 反擊數