首页 > 代码库 > POJ3708 Recurrent Function

POJ3708 Recurrent Function

【题意】

  给出一个正整数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 }
View Code

  说实话写的有点丑。。。。

POJ3708 Recurrent Function