2020牛客多校第四场D-Dividing Strings
https://ac.nowcoder.com/acm/contest/5669/D
题意
给出一个由数字构成的字符串,把字符串分成若干不含前导零的子串,求子串间最大差值的最小值
题解
首先可以分成全部长度为1,所以答案一定小于等于9
所以划分只有两种情况,要么全部长度相等,要么最长的和最短的相差1
对于第一种情况,直接枚举约数扫一遍
对于第二种情况,合法的一定是10000...y和9999...x这样类似的,先找到构成10000...y的长度是多少(len),然后分别判断len是否可行和len-1是否可行
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct READ {
inline char read() {
#ifdef _WIN32
return getchar();
#endif
static const int IN_LEN = 1 << 18 | 1;
static char buf[IN_LEN], *s, *t;
return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
}
template <typename _Tp> inline READ & operator >> (_Tp&x) {
static char c11, boo;
for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
if(c11 == -1) return *this;
boo |= c11 == '-';
}
for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
boo && (x = -x);
return *this;
}
} in;
const int N = 2e5 + 50;
char s[N];
int n;
int ans;
int cmx[N], cmn[N], cnow[N];
bool cmp(int a[], int b[], int len) {
for (int i = 1; i <= len; i++) if (a[i] != b[i]) return a[i] > b[i];
return 0;
}
void copy(int a[], int b[], int len) {
for (int i = 1; i <= len; i++) a[i] = b[i];
}
void check(int len) {
for (int j = 1; j <= len; j++) cmn[j] = 9, cmx[j] = 0;
for (int j = 1; j <= n; j++) {
if (j % len == 1 && s[j] == '0') return;
cnow[(j-1)%len+1] = s[j] - '0';
if (j % len == 0) {
if (cmp(cnow, cmx, len)) copy(cmx, cnow, len);
if (cmp(cmn, cnow, len)) copy(cmn, cnow, len);
}
}
int mni = 9;
for (int j = len; j >= 1; j--) {
int t = cmx[j] - cmn[j];
if (t < 0) cmx[j - 1]--, t += 10;
if (j == len) mni = t;
else if (t > 0) return;
}
ans = min(ans, mni);
}
int find() {
for (int now = 1; now <= n; now++) {
if (s[now] == '1') {
int l = now;
while (now < n && s[now + 1] == '0') now++;
if (now < n && s[now + 1] != '9') now++;
return now - l + 1;
}
}
return -1;
}
int calc(int len) {
int n1 = -1, n9 = 10;
for (int now = 1; now <= n; now++) {
int l = now;
if (s[now] == '1') {
while (now < n && s[now + 1] == '0') now++;
if (now < n && now - l + 1 < len && s[now + 1] != '9') now++;
if (now - l + 1 != len) return 9;
n1 = max(n1, s[now] - '0');
}
else {
now--;
while (now < n && s[now + 1] == '9' && now - l + 1 < len - 1) now++;
if (now < n && now - l + 1 < len - 1) now++;
if (now - l + 1 != len - 1) return 9;
n9 = min(n9, s[now] - '0');
}
}
if (n9 == 10 || n1 == -1) return 9;
return n1 + 10 - n9;
}
int main() {
int t; scanf("%d", &t);
while (t--) {
scanf("%d", &n);
scanf("%s", s + 1);
int mxi = 0, mni = 1e9;
for (int i = 1; i <= n; i++) {
mxi = max(mxi, s[i] - '0');
mni = min(mni, s[i] - '0');
}
ans = mxi - mni;
for (int i = 2; i < n; i++) {
if (n % i == 0) check(i);
}
int len = find();
if (len > 1) ans = min(ans, calc(len));
if (len > 2) ans = min(ans, calc(len - 1));
printf("%d\n", ans);
}
return 0;
}