题目描述
Bipartite Number是这样的一个正整数,他只能由两段相同的数组成,如44444411,10000000, 5555556,41,而4444114,44444则不是。
现给你一个N,让你找到最小的Bipartite NumberX,使得X=NK(K是正整数),由于答案X可能很大,你需将其缩写转换为4个数字输出,即(高位数字长度,高位数字,低位数字长度,低位数字),如44444411为6 4 2 1,88888888888800000为12 8 5 0
输入格式
若干行,每行一个数字,
最后以0结束结尾。
输出格式
对于每一行输入输出4个数字用一个空格隔开,行末无多余空格。
样例输入
125
17502
2005
0
样例输出
1 5 2 0
4 7 4 8
3 2 3 5
100%:N<=10^5 每个测试点不会超过20组数据
题解:
预先计算好两个数列。
数列1:a[1]=1,a[i+1]=(a[i]*10+1) mod N,i = 1,2,3,… a[i]就是连续i个1除以N的余数。
数列2:b[0]=1,b[i+1]=b[i]*10 mod N,i = 0,1,2,3,… b[i]就是10的i次方除以N的余数。
有了这两个数列,只需用O(1)的时间就可以计算任意二段数除以N的余数。假设二段数是由
m个s和n个t组成,二段数m,s,n,t除以N的余数等于(a[m]*b[n]*s+a[n]*t) mod N。
接下来只要枚举m,s,n,t就可以了。按照(m+n)的值从小到大枚举,(m+n)确定后枚举m,则n
可以直接计算出来,不需要枚举。m和n确定之后枚举s和t。一旦找到解,后面的(m+n)值就不
需要继续枚举下去了。为了减少不必要的枚举,可以先进行判断。例如,N是10的倍数时,t只
能取0。
AC-Code:
#include<cstdio>
#include<cstring>
#include <algorithm>
#define maxn 100100
#define rint register int
#define inf 30000
using namespace std;
short mxva[21][maxn * 9];
short mnva[21][maxn * 9];
int n, tn;
int p1[maxn * 21];
int p2[maxn * 21];
int p_cnt = 0;
int tmp[11];
int tmp_cnt = 0;
int a, b, c, d;
int i, j, x, y;
inline bool check() {
return !(x - y == a && i == b && y == c && j == d);
}
int main() {
while (scanf("%d", &n)) {
if (n == 0) break;
tmp_cnt = 0;
int ttn = n;
while (n) tmp[++tmp_cnt] = n % 10, n /= 10;
bool fl = 0;
a = 1, b = tmp[tmp_cnt], c = 0, d = 0;
for (i = tmp_cnt - 1; i >= 1; --i) {
if (fl && tmp[i] != tmp[i + 1]) { a = -1, b = -1, c = -1, d = -1; break; }
else if ((!fl) && tmp[i] != tmp[i + 1]) fl = 1, d = tmp[i];
if (fl) c++;
else a++;
}
if (!fl) a = -1, b = -1, c = -1, d = -1;
n = ttn; tn = n * 9;
int now = 1;
for (x = 1;; x++) {
now = now * 10 % tn;
for (i = 1; i < 10; i++) {
int nowj = 11, nowy = -1;
for (j = 0; j < i; j++) {
int tmp = (i * now - j + tn) % tn;
if (mxva[i - j + 10][tmp]) {
y = mxva[i - j + 10][tmp];
if (!check()) continue;
if (y > nowy || (y == nowy && j < nowj)) nowj = j, nowy = y;
}
}
if (nowj != 11) { y = nowy, j = nowj; goto find; }
nowy = inf;
for (j = i + 1; j < 10; j++) {
int tmp = (i * now - j + tn) % tn;
if (mnva[i - j + 10][tmp]) {
y = mnva[i - j + 10][tmp];
if (!check()) continue;
if (y < nowy || (y == nowy && j < nowj)) nowj = j, nowy = y;
}
}
if (nowj != 11) { y = nowy, j = nowj; goto find; }
}
for (i = -10; i <= 10; i++) {
int tt = (i * now % tn + tn) % tn;
mxva[i + 10][tt] = max((short)x, mxva[i + 10][tt]);
if (!mnva[i + 10][tt]) mnva[i + 10][tt] = inf;
mnva[i + 10][tt] = min((short)x, mnva[i + 10][tt]);
p1[++p_cnt] = i + 10;
p2[p_cnt] = tt;
}
}
find:
printf("%d %d %d %d\n", x-y, i, y, j);
for (i = 1; i <= p_cnt; i++) mxva[p1[i]][p2[i]] = 0, mnva[p1[i]][p2[i]] = 0;
p_cnt = 0;
}
return 0;
}