poj3708(公式化简+大数进制装换+线性同余方程组)

刚看到这个题目,有点被吓到,毕竟自己这么弱。

分析了很久,然后发现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;
}
时间: 2024-10-06 01:15:13

poj3708(公式化简+大数进制装换+线性同余方程组)的相关文章

进制装换

[一些常识] integer == int 整数decimal == 十进制数的binary == bin 二进制octal = oct 八进制hexadecimal == hex 十六进制 %d 整数%f 浮点%s 字符串%x 十六进制数%o 八制数 在shell脚本中的进制转换 #转换成十进制printf "%d\n" 11printf "%d\n" \"a\"#保留一位小数printf "%0.1f\n" 11#转换成八

大数进制转换问题

在数据结构课关于栈的这一章中,我们都学过用"模2取余法"来将一个10进制数转换为一个二进制数,进而可以推广到"模n取余法",经其转换为n进制(n任意指定). 确实,这是一个很基础的题目,可你是否想过如果这个10进制数是一个大数(其位数可能上千位,此时用一般数据类型肯定是会溢出的),那么这个问题又如何来求解呢? 当然,也许你会说很简单嘛,自己写一个大数类(当然至少要写一个大数除法才行),或者你用的是Java这种现代化语言,就更轻松了,直接用BigInteger这样的大

poj3708:函数式化简+高精度进制转换+同余方程组

题目大意 给定一个函数 找出满足条件   等于 k 的最小的x m,k,d已知 其中 m,k 很大需要使用高精度存储 思路: 对 函数f(m)进行化简 ,令t=ceil( log(d,m) ) 可以得到 f(m)=d ^ t * ( a [ m / (d^t) ] ) + d ^ (t-1) * ( b[ m/( d^(t-1) ) ] )......+b [m%d] : 我们一看,每一项都是 跟 d 的次方有关,所以考虑使用 d 进制进行计算 设     m=a1b1b2b3b4(d进制) 那

2015年4月27日----高大上的数组,进制准换,最多是35进制

#include <stdio.h>#include <stdlib.h>#include <string.h> int main(int argc, char *argv[]){ /*十进制准换城任何进制的程序*/ int ival, base; //ival 是十进制数,base 是要转换的进制 int index =0; char arr[32]; memset(arr, 0, sizeof(arr)); printf("input the ival a

大数进制转换

给出一个36进制的大数(0-9,A-Z),将其转为10进制并输出. Input输入:36进制的大数,每一位用0-9,A-Z来表示,A表示10,Z表示35.(A的长度 <= 100000)Output输出:该数的10进制表示Sample Input 1AZ Sample Output 1691 起初做大数据处理的题目,并没有什么功底,就是突然想到可以用数组,所以再次做到这类题时,仍然记得用数组存位,最后倒着输出就好 所以原始是这么写的 超时代码1 #include <iostream> #

POJ1220(大数进制转换)

NUMBER BASE CONVERSION Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4652   Accepted: 2132 Description Write a program to convert numbers in one base to numbers in a second base. There are 62 different digits: { 0-9,A-Z,a-z } HINT: If

hdu-1877(大数+进制转换)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1877 思路:注意考虑0,0的情况. #include<iostream> #include<cstdio> #include<string> #include<algorithm> using namespace std; int m,a,b; string s1,s2; string add(string s1,string s2) { if(s1.lengt

delphi 进制转换

----二进制到16进制 function BinaryToHex(strBinary: string): string;var  vD: Byte;  i: integer;  vHextStr: String;  vP: PChar;  vLen: integer;begin  vLen := length(strBinary);  if vLen mod 4 > 0 then  begin    SetLength(vHextStr, vLen div 4 + 1);    vLen :=

delphi -- 进制转换 函数表

1.16 TO 10 ******************************************************** 16转10,否则输出-1 function Hex(c: char): Integer;var  x: Integer;begin  if ( Ord(c)>= Ord('0')) and (Ord(c) <= Ord('9')) then    x:= Ord(c) - Ord('0')  else if (Ord(c) >= Ord('a')) an