题目
[CodeFoeces 1051E] Vasya and Big Integers
分析
用双指针维护 d p [ i ] dp[i] dp[i] 的转移范围,问题的难点就是快速比较两个字符串的大小。比较两个字符串的大小转化为比较 LCP 的后一个字符的大小,因此 Hash + 二分即可。
要注意处理前导零的问题。
找 LCP 的时候先暴力比前面的几位,否则会被卡 Hash。
真就调了整整一天。
代码
调得很暴躁,代码不好看。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
typedef long long LL;
typedef unsigned long long ULL;
const int MAXN = 1000000;
const int MOD = 998244353;
int N, P, Q;
int Dp[MAXN + 5];
const ULL PRI = 2333;
ULL Pow[MAXN + 5];
struct Hash {
int Len;
char S[MAXN + 5];
ULL Num[MAXN + 5];
void Init() {
Len = strlen(S + 1);
for (int i = 1; i <= Len; i++)
Num[i] = Num[i - 1] * PRI + S[i] - '0';
}
int Key(int lft, int rgt) const {
return Num[rgt] - Num[lft - 1] * Pow[rgt - lft + 1];
}
}A, L, R;
int FuckTheLead0(int st, int ed) {
int lft = st - 1, rgt = ed;
while (lft + 1 < rgt) {
int mid = (lft + rgt) >> 1;
if (A.Key(st, mid) == 0)
lft = mid;
else
rgt = mid;
}
return lft + 1;
}
int Comp(int st, int ed, const Hash &str) {
st = FuckTheLead0(st, ed);
if (ed - st + 1 != str.Len)
return ed - st + 1 > str.Len ? 1 : -1;
int tmp = std::min(st + 100, ed);
for (int i = st; i <= tmp; i++)
if (A.S[i] != str.S[i - st + 1])
return A.S[i] < str.S[i - st + 1] ? -1 : 1;
if (tmp == ed)
return 0;
int lft = tmp - st, rgt = ed - st + 2;
while (lft + 1 < rgt) {
int mid = (lft + rgt) >> 1;
if (A.Key(st, st + mid - 1) == str.Key(1, mid))
lft = mid;
else
rgt = mid;
}
if (lft == ed - st + 1)
return 0;
return A.S[st + lft] < str.S[lft + 1] ? -1 : 1;
}
bool Lead0(int i, int len) {
if (len == 1) return false;
return A.S[i] == '0';
}
int main() {
Pow[0] = 1;
for (int i = 1; i <= MAXN; i++)
Pow[i] = Pow[i - 1] * PRI;
scanf("%s%s%s", A.S + 1, L.S + 1, R.S + 1);
A.Init(), L.Init(), R.Init();
Dp[0] = 1;
int sum = 1, lft = 0, rgt = 0;
std::set<int> S; S.insert(0);
// if (A.S[1] == '1' && A.S[2] == '2' && A.S[3] == '2' && A.S[6] == '1')
// printf("%d %d\n", Comp(1, L.Len, L), Comp(1, L.Len, R));
Dp[L.Len] = Comp(1, L.Len, L) >= 0 && Comp(1, L.Len, R) <= 0;
for (int i = L.Len + 1; i <= A.Len; i++) {
// if (i == 8)
// puts("What's the shit Fucking about?");
int tmp = 0;
while (rgt < i - 1 && Comp(rgt + 2, i, L) >= 0) {
++rgt;
bool flag = true;
if (A.S[rgt + 1] == '0' && rgt + 1 == i)
tmp = (tmp + Dp[rgt]) % MOD, flag = false;
if (!Lead0(rgt + 1, i - rgt)) {
sum = (sum + Dp[rgt]) % MOD;
if (flag) S.insert(rgt);
}
}
while ((lft <= rgt && Comp(lft + 1, i, R) > 0) || Lead0(lft + 1, i - lft)) {
if (S.count(lft))
sum = ((sum - Dp[lft]) % MOD + MOD) % MOD, S.erase(lft);
lft++;
}
Dp[i] = sum;
// printf("%d [%d, %d] Dp = %d sum = %d\n", i, lft, rgt, Dp[N], sum);
sum = ((sum - tmp) % MOD + MOD) % MOD;
// printf(" -> %d\n", sum);
}
// if (A.S[1] == '1' && A.S[2] == '2' && A.S[3] == '2' && A.S[6] == '1') {
// printf("%d\n%d\n%d\n", A.Len, L.Len, R.Len);
// for (int i = 1; i <= 20; i++)
// printf("%c", L.S[i]);
// puts("");
// for (int i = 1; i <= 20; i++)
// printf("%c", R.S[i]);
// puts("");
// printf("[%d, %d] Dp = %d sum = %d\n", lft, rgt, Dp[N], sum);
// }
printf("%d", Dp[A.Len]);
return 0;
}