传送门:POJ 3708
题解
(1)设m, k的d进制表示分别为p1p2···pn1,
k1k2···kn2
其中n1, n2是位数
(2)由 f(m) 定义得:
f(m)=ap1∗dn−1+∑i=2n(bpi∗dn−i),ap1ϵ[1,d),(bpiϵ[0,d),iϵ[2,n)]
(3) 所以 f(m) 的d进制形式为a p1b p2···b pn1, 由此可知m和 f(m) 的在d进制下的表示位数是相同的, 所以若
fx(m)=k 存在解, 必须满足
n1 = n2
(4)此外, 根据 (3)
还能得到 :
fx(m)
的d进制是m的d进制各位上x次置换,首位是a上的置换,其余如果存在是在b上的置换
(5) 现考虑pi->ki,若果pi和ki在i所在置换上在一个环内, 则存在一个最小的置换次数记lefti, 满足pi经过lefti次置换后变成ki, 且之后每经过该环大小(记为modi)次置换,都能变为ki, 所以若存在
fx(m)=k
, n1 = n2
且 pi和ki(
iϵ[1,n]
)其所在置换内都在一个环中(抽象代数置换知识), 且 x满足:
x≡lefti(modmodi),iϵ[1,n]
(6) 中国剩余定理两两合并可解
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 105;
int d;
int a[N], b[N];
int aa[410], bb[410], mod[410], left[410], in1[110], in2[110];
char s1[110], s2[110];
/**高精度转d进制*/
void tran(int ten[], int len, int &cnt, int tmp[]){
cnt = 0;
int tcnt = 0;
while(tcnt < len){
for(int i = tcnt; i < len; ++i){
ten[i + 1] += (ten[i] % d) * 10;
ten[i] /= d;
}/**模拟除法,余数 * 10存在ten[len]中*/
tmp[cnt++] = ten[len] / 10;
ten[len] = 0;
while(ten[tcnt] == 0 && tcnt < len) ++tcnt;
}
}
void getModAndLeft(int len){/**获取模数和余数*/
int id = len - 1;
mod[id] = 1;
int cnt = 0;
if(aa[id] == bb[id]) left[id] = 0;
for(int i = a[aa[id]]; i != aa[id]; i = a[i]){
++mod[id];
++cnt;
if(i == bb[id]) left[id] = cnt;
}
for(int i = 0; i < id; ++i){
if(aa[i] == bb[i]) left[i] = 0;
mod[i] = 1;
cnt = 0;
for(int j = b[aa[i]]; j != aa[i]; j = b[j]){
++mod[i];
++cnt;
if(j == bb[i]) left[i] = cnt;
}
}
/**printf("test\n");*/
}
ll extend_gcd(ll a, ll b, ll &x, ll &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
ll d = extend_gcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main(){
while(~scanf("%d", &d), ~d){
memset(left, -1, sizeof left);
for(int i = 1; i < d; ++i){
scanf("%d", a + i);
}
for(int i = 0; i < d; ++i){
scanf("%d", b + i);
}
scanf("%s%s", s1, s2);
int len1 = strlen(s1), cnt1;
for(int i = len1 - 1; i >= 0; --i) in1[i] = s1[i] - '0';
int len2 = strlen(s2), cnt2;
for(int i = len2 - 1; i >= 0; --i) in2[i] = s2[i] - '0';
tran(in1, len1, cnt1, aa);
tran(in2, len2, cnt2, bb);
if(cnt1 == cnt2){/**判断位数*/
getModAndLeft(cnt1);
bool f = 0;
for(int i = 0; i < cnt1; ++i) if(left[i] == -1) f = 1;/**判断是否不在一个环*/
if(f) puts("NO");
else{
ll modNum = mod[0] * 1ll, leftNum = left[0] * 1ll, x, y;
for(int i = 1; i < cnt1; ++i){/**两两合并*/
ll c = left[i] * 1ll - leftNum;
ll m1 = modNum, m2 = mod[i] * 1ll;
ll d = extend_gcd(modNum, m2, x, y);
if(c % d){
f = 1;
break;
}
x *= c / d;
ll t = m2 / d;
x = (x % t + t) % t;
modNum *= t;
leftNum = (leftNum + x * m1) % modNum;
}
if(f) puts("NO");
else printf("%lld\n", leftNum);
}
}else puts("NO");
}
return 0;
}