【题意】
给出一个正整数d(2<=d<=100);一个元素个数为d-1的集合a,每个集合元素ai对应一个1~d-1的整数;以及定义相同的大小为d集合bi。
f函数的定义原题已给出。求数m最少经过多少次函数操作变为数k,无解输出NO。
【题解】
我们可发现当x>=d时,f(x)=d*f(x/d)+b[x mod d],x<d时,f(x)=a[x]。
不难发现其实这就是在x的d进制下,对每一位进行变换,某一位如果是x,要么变a[x],要么变b[x]。所以答案就是当某一次操作后,每一位都与目标数一致。
于是对m在d进制下的每一位找第一次到达目标数的次数以及循环节(之所以有a与b两个集合就是防止最高位变为0)。最后就成了求n个模线性方程组求解的问题。
【代码】
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #define ll long long 6 using namespace std; 7 struct node 8 { 9 ll a,r; 10 }a[1000]; 11 int n,A[105],B[105],flag[105],po[1000],sum[1000],c[1000],d[1000]; 12 ll D; 13 char st[105]; 14 int read() 15 { 16 int x=0,sign=1;char ch; 17 do{ch=getchar();if(ch=='-')sign=-sign;}while(ch<'0'||ch>'9'); 18 do{x=x*10+ch-48;ch=getchar();}while(ch>='0'&&ch<='9'); 19 return x*sign; 20 } 21 void exgcd (ll a,ll b,ll &x,ll &y) 22 { 23 if (b==0) 24 { 25 D=a; 26 x=1; 27 y=0; 28 return; 29 } 30 exgcd(b,a%b,x,y); 31 ll t=x; 32 x=y; 33 y=t-a/b*y; 34 } 35 ll crt(node a[],int n) 36 { 37 for (int i=1;i<=n;++i) if (a[i].r==-1) return -1; 38 ll A=a[1].a,R=a[1].r,x,y,q; 39 for (int i=2;i<=n;++i) 40 { 41 exgcd(A,-a[i].a,x,y); 42 if ((a[i].r-R)%D)return -1; 43 q=-a[i].a/D; 44 x=(a[i].r-R)/D%q*x%q; 45 R=A*x+R; 46 A=q*A; 47 } 48 if (A<0) A=-A; 49 return (R%A+A)%A; 50 } 51 node rpt(int A[],int n,int x,int y) 52 { 53 int cnt=0; 54 for (int i=0;i<=n;++i) flag[i]=0; 55 while (!flag[x]) 56 flag[x]=++cnt,x=A[x]; 57 return {cnt,flag[y]-1}; 58 } 59 void div(int sum[],int d) 60 { 61 po[0]=0;int x=0; 62 for (int i=1;i<=sum[0];++i) 63 { 64 x=x*10+sum[i]; 65 if (!po[0] && x>=d || po[0]) 66 po[++po[0]]=x/d,x%=d; 67 } 68 sum[0]=po[0]; 69 for (int i=1;i<=po[0];++i) sum[i]=po[i]; 70 } 71 int mo(int sum[],int d) 72 { 73 int x=0; 74 for (int i=1;i<=sum[0];++i) 75 { 76 x=x*10+sum[i]; 77 if (x>=d) x=x%d; 78 } 79 return x; 80 } 81 void get(int c[],int d) 82 { 83 scanf("%s",st+1); 84 sum[0]=strlen(st+1); 85 for (int i=1;i<=sum[0];++i) 86 sum[i]=st[i]-48; 87 c[0]=0; 88 while (sum[0]) 89 { 90 c[++c[0]]=mo(sum,d); 91 div(sum,d); 92 } 93 for (int i=1;i+i<=c[0];++i) swap(c[i],c[c[0]-i+1]); 94 } 95 int main() 96 { 97 while (1) 98 { 99 n=read(); 100 if (n==-1) break; 101 for (int i=1;i<n;++i) A[i]=read(); 102 for (int i=0;i<n;++i) B[i]=read(); 103 get(c,n);get(d,n); 104 if (c[0]!=d[0]){puts("NO");continue;} 105 a[1]=rpt(A,n-1,c[1],d[1]); 106 for (int i=2;i<=c[0];++i) a[i]=rpt(B,n,c[i],d[i]); 107 ll ans=crt(a,c[0]); 108 if (ans==-1) puts("NO"); 109 else printf("%I64d\n",ans); 110 } 111 return 0; 112 }
说实话写的有点丑。。。。