刚看到这个题目,有点被吓到,毕竟自己这么弱。
分析了很久,然后发现m,k都可以唯一的用d进制表示。也就是用一个ai,和很多个bi唯一构成。
这点就是解题的关键了。 之后可以发现每次调用函数f(x),相当于a(ai),b(bi)了一下。这样根据置换的一定知识,一定会出现循环,而把循环的大小看成取模,把从m->k的看成余,于是可以建立一个线性同余方程。
直接用模板解决之。。
Recurrent Function
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1102 | Accepted: 294 |
Description
Dr. Yao is involved in a secret research on the topic of the properties of recurrent function. Some of the functions in this research are in the following pattern:
in which set {ai} = {1, 2, …, d-1} and {bi} = {0, 1, …, d-1}.
We denote:
Yao‘s question is that, given two positive integer m and k, could you find a minimal non-negative integer x that
Input
There are several test cases. The first line of each test case contains an integer d (2≤d≤100). The second line contains 2d-1 integers: a1, …, ad-1, followed by b0, ..., bd-1. The third line contains integer m (0<m≤10100), and the forth line contains integer k (0<k≤10100). The input file ends with integer -1.
Output
For each test case if it exists such an integer x, output the minimal one. We guarantee the answer is less than 263. Otherwise output a word "NO".
Sample Input
2 1 1 0 4 7 2 1 0 1 100 200 -1
Sample Output
1 NO
Hint
For the first sample case, we can see that f(4)=7. And for the second one, the function is f(i)=i.
// // main.cpp // poj3708 // // Created by 陈加寿 on 15/11/28. // Copyright (c) 2015年 陈加寿. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> using namespace std; int a[110],b[110]; char strm[110],strk[110]; int m[110],k[110]; int savem[1100],savek[1100]; int cntm,cntk; void Tentod(int ten[],int len,int &cnt,int d,int save[]) { int tcnt=0; while(ten[tcnt]==0) tcnt++; cnt=0; while(tcnt<len) { for(int i=tcnt;i<len;i++) { ten[i+1] += (ten[i]%d)*10; ten[i] /= d; } save[cnt++] = ten[len]/10; ten[len]=0; while(tcnt<len&&ten[tcnt]==0) tcnt++; } /* for(int i=0;i<cnt;i++) printf("%d ",save[i]); printf("\n"); */ } /*对于x=r0(mod m0) x=r1(mod m1) ... x=rn(mod mn) 输入数组m和数组r,返回[0,[m0,m1,...,mn]-1] 范围内满足以上等式的x0。 x的所有解为:x0+z*[m0,m1,...mn](z为整数) */ long long cal_axb(long long a,long long b,long long mod) { //防乘法溢出 long long sum=0; while(b) { if(b&1) sum=(sum+a)%mod; b>>=1; a=(a+a)%mod; } return sum; } //ax + by = gcd(a,b) //传入固定值a,b.放回 d=gcd(a,b), x , y void extendgcd(long long a,long long b,long long &d,long long &x,long long &y) { if(b==0){d=a;x=1;y=0;return;} extendgcd(b,a%b,d,y,x); y -= x*(a/b); } long long Multi_ModX(long long m[],long long r[],int n) { long long m0,r0; m0=m[0]; r0=r[0]; for(int i=1;i<n;i++) { long long m1=m[i],r1=r[i]; long long k0,k1; long long tmpd; extendgcd(m0,m1,tmpd,k0,k1); if( (r1 - r0)%tmpd!=0 ) return -1; k0 *= (r1-r0)/tmpd; m1 *= m0/tmpd; r0 = ( cal_axb(k0,m0,m1)+r0)%m1; m0=m1; } return (r0%m0+m0)%m0; } int main(int argc, const char * argv[]) { int d; while(cin>>d) { if(d==-1) break; for(int i=1;i<d;i++) cin>>a[i]; for(int i=0;i<d;i++) cin>>b[i]; scanf("%s",strm); scanf("%s",strk); int len = strlen(strm); for(int i=0;i<len;i++) m[i] = strm[i]-‘0‘; Tentod(m,len,cntm,d,savem); len = strlen(strk); for(int i=0;i<len;i++) k[i] = strk[i]-‘0‘; Tentod(k, len, cntk, d, savek); // 这样就得到了。a,b。。。 // 然后构建同模方程 if(cntm != cntk) { printf("NO\n"); } else { int flag=0; long long m[1010],r[1010]; for(int i=0;i<cntm-1;i++) { int a1=savem[i],a2=savek[i]; int tm=1; int ta=a1; while(b[ta]!=a1) { tm++; ta=b[ta]; } ta=a1; int tr=0; while(ta != a2) { tr++; ta=b[ta]; if(ta==a1) { flag=1; break; } } m[i]=tm; r[i]=tr; if(flag==1) break; }//这里面都是b int a1=savem[cntm-1],a2=savek[cntm-1]; int tm=1; int ta=a1; while(a[ta]!=a1) { tm++; ta=a[ta]; } ta=a1; int tr=0; while(ta != a2) { tr++; ta=a[ta]; if(ta==a1) { flag=1; break; } } m[cntm-1]=tm; r[cntm-1]=tr; if(flag == 1) { printf("NO\n"); } else { long long ans=Multi_ModX(m, r,cntm); if(ans==-1) printf("NO\n"); else cout<<ans<<endl; } } } return 0; }