acm fzu 2108 Mod problem

来源:互联网 发布:客户管理源码 编辑:程序博客网 时间:2024/06/01 09:39

Accept: 17    Submit: 50
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

Given one non-negative integer A and one positive integer B, it’s very easy for us to calculate A Mod B. Here A Mod B means the remainder of the answer after A is divided by B. For example, 7 Mod 5 = 2, 12 Mod 3 = 0, 0 Mod 3 = 0.

In this problem, we use the following rules to express A.

(1) One non-empty string that only contains {0,1,2,3,4,5,6,7,8,9} is valid.

For example, 123, 000213, 99213. (Leading zeros is OK in this problem)

(2) If w is valid, then [w]x if valid. Here x is one integer that 0<x<10.

For example, [012]2=012012, [35]3[7]1=3535357.

(3) If w and v are valid, then wv is valid.

For example, w=[231]2 and v=1, then wv=[231]21 is valid (which is 2312311).

Now you are given A and B. Here A is express as the rules above and B is simply one integer, you are expected to output the A Mod B.

 Input

The first line of the input contains an integer T(T≤10), indicating the number of test cases.

Then T cases, for any case, only two lines.

The first line is one non-empty and valid string that expresses A, the length of the string is no more than 1,000.

The second line is one integer B(0<B<2,000,000,000).

You may assume that the length of number A in decimal notation will less than 2^63.

 Output

For each test case, output A Mod B in a single line.

 Sample Input

3[0]9[[1]2]310007[[213231414343214231]5]110007[0012]11

 Sample Output

103439430

 Source

“高教社杯”第三届福建省大学生程序设计竞赛
哼,我终于A了,这是福大武核出的题,我在贴吧问这道题时,他说建树然后遍历一遍就OK。。。但他不说怎么构树,说了等于没说


但这不能阻止我AC,哼,说白了就是快速取模

快速模取幂

    数论计算中经常出现的一种运算就是求一个数的幂ab对另外一个数n个模的运算,即计算:

ab mod n (a,b,n是正整数)

    由于计算机只能表示有限位的整数,所以编程时模取幂的运算要注意值的大小范围,当ab的值超过整数范围时,mod运算便无法进行。

    如何解决这个问题,我们引出一个能计算ab mod n的值的有用算法——反复平方法,首先我们必须明确:

d=ab mod n=(…((((a mod n)*a)mod n)*a)mod n…*a)mod n    {共b个a}

    由此可以引出一个迭代式

         d:=a;

         for i:=2 to b do

            d:=d mod n*a;

         d:=d mod n;

    时间复杂度为O(b),当b很大时,效率很低。我们可以将b转换为二进制数<bk,bk-1,...,b1,b0>,然后从最低位b0开始,由右至左逐位扫描,每次迭代时,用到下面两个恒等式:

a2c mod n =(ac)2 mod n      bi=0            

a2c+1 mod n =a*(ac)2 mod n   bi=1 (0<=c<=b)

    其中c为b的二进制数的后缀(bi-1...b0)对应的十进制数,当c成倍增加时,算法保持d=ac mod n不变,直至c=b。

     程序实现可如下:

long long result(long long a,long long b,long long m)
{
    long long d,t;

    d=1;
    t=a;
    while (b>0)
    {
        if (b%2==1)
            d=(d*t)%m;
        b/=2;
        t=(t*t)%m;
    }

    return d;
}

/*快速幂int pow(int a ,int k){    int rec = 1;    while( k )    {        if (k & 1)            rec *= a;        a *= a;        k >>= 1;    }    return rec;}  & 表示的是k这一位是否为一,K>>= 表示K的位置右移以为,while(K)是直到K移到最后一位的时候弹出.举个例子,3^13;13=1*2^3+1*2^2+0*2^1+1*2^0;那么第一次K=13;这个时候K&1表示探查2^0的这一位是否为1;为1,则进行rec*=a; k>>=1表示将13右移一位,即13/2;可以在之前的13的上面直接表示出来.6=1*2^2+1*2^1+0*2^0;这个时候,k&1则为0了。因为2^0的系数是0;快速幂取模int ModPow(int a,int b,int n){    int rec=1;    while(b)    {        if (b & 1)            rec = (rec * a) % n;        a = (a * a) % n;        b >>= 1;    }    return rec % n;}模运算规则:模运算与基本四则运算有些相似,但是除法例外。其规则如下:(a + b) % p = (a % p + b % p) % p(a – b) % p = (a % p – b % p) % p(a * b) % p = (a % p * b % p) % pab % p = ((a % p)b) % p结合率:((a+b) % p + c) % p = (a + (b+c) % p) % p((a*b) % p * c)% p = (a * (b*c) % p) % p*/#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define N 1010char s[N];long long m;struct node{long long v,k;//位数};long long qmod(long long a,long long k){//快速取模long long v=1;//while(--k)v=(v*10)%m;while(k){if(k&1)v=(v*a)%m;a=(a*a)%m;k>>=1;}return v%m;}node build(int l,int r){node p={0},t;int i,flag=0;int x,y,k;for(i=l;i<=r;i++){if(s[i]=='['){if(flag==0)x=i+1;flag++;}else if(s[i]==']'){flag--;if(flag==0){//找到最外的[]y=i-1;i++;k=s[i]-'0';t=build(x,y);//得到[]里的位数m,和取模后的v//cout<< "【"<<k<<"】"<<x<<" "<<y<<endl;long long h=qmod(10,t.k);long long g=1,e=h;//cout<<t.k<<" "<<h<<endl;p.k+=k*t.k;//总位数加上p.v=(p.v*qmod(h,k))%m;//p.v*(10^t.k)//t.v=qmod(t.v,k);//t.v^k************while(--k){g+=e;e=(e*h)%m;if(g>=m)g%=m;}//cout<<t.v<<"-----"<<g<<endl;t.v=(t.v*g)%m;p.v=(p.v+t.v)%m;//cout<<p.v<<"*****"<<p.k<<endl;}}else if(flag==0){//数字p.v=p.v*10+s[i]-'0';if(p.v>=m)p.v%=m;p.k++;//位数加1}}return p;}int main(){int T;//m=7;printf("%lld\n",qmod(10,2));scanf("%d",&T);while(T--){scanf("%s%lld",s,&m);printf("%lld\n",build(0,strlen(s)-1).v);}return 0;}