• 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

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

  • 相关阅读:
    开发细节
    html
    java学习
    Promise对象
    强制转换和隐式转换
    借助防抖解决输入框的非空校验
    setTimeout
    Symbol类型
    js API
    vue 使用mixin
  • 原文地址:https://www.cnblogs.com/Bleacher/p/6869339.html
Copyright © 2020-2023  润新知