HDU-5238 Calculator

题目描述

给定一个关于 \(x\) 的表达式,形如下例:\(×4+2^3+8×6\)
按如下方法计算:\((((x×4)+2)^3+8)×6\)
运算符只有 加号,乘号,幂运算三种,给定的式子中有 \(n\)次运算。
进行 \(m\)次给定的操作:

1.表示对一个给定的 \(x\) 值,求原式的结果并对 \(29393\) 取模;

2.表示将 \(k\) 位置上的运算符和运算符后面的数字改变。完成这些操作。

Input

有多组数据。

\(1≤n,m≤50000\)

Output

对于每组数据输出答案。

Sample Input

2
5 4
*4
+2
^3
+8
*6
1 2
1 3
2 3 *5
1 3
4 3
*4
^4
+4
*10
1 1
2 3 ^4
1 1

Sample Output

Case #1:
6048
16512
468
Case #2:
2600
4107

让我们来看一下这个奇特的模数\(29393=7*13*17*19\)

至于有什么用呢?我们先往下看。

首先,我们需要去快速的查询一个数经过这\(n\)个操作的值,同时我们需要支持快速修改的操作。

待修改的数据结构,还有区间查询我们直接就想到的线段树。

我们该如何转移呢?


对于当前区间\(L,R\),编号为\(num\),未知数为\(x\)的结果为\(F(x,L,R,num)\)

考虑两个子区间合并。

\(val=F(x,L,mid,num<<1|1)\),即\(x\)经过左子区间的答案。

那我们就有了\(F(x,L,R,num)=F(val,mid+1,R,num<<1|1)\)

于是我们就可以利用线段树快速进行求解的。


我们仔细看看,模数为\(29393\),线段数对于每个小于等于模数的数都要储存答案。

空间复杂度为\(O(4*n*模数)\),时间复杂度为\(O(n*log_n*模数)\)

无论是时间还是空间都无法承受。

现在,让我们再看一下之前所提到的\(29393\)

我们把它分解为\(7*13*17*19\)

我们发现,对于这\(4\)个数作为模数的时间和空间复杂度都是可以承受的。

那么设当前\(x\)经过这\(4\)个模数的答案为\(res_i\),最终答案为\(Ans\),我们有:

\[\begin{cases} Ans=res_1\%p_1 \\ Ans=res_2\%p_2 \\ Ans=res_3\%p_3 \\ Ans=res_4\%p_4 \end{cases} \]

我们直接利用中国剩余定理求解即可。

#include <cstdio>
#include <iostream>

using namespace std;

#define LL long long
#define reg register
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define abs(a) ((a)<0?-(a):(a))
#define debug(x) cerr<<#x<<"="<<x<<endl;
#define debug2(x,y) cerr<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl;
#define debug3(x,y,z) cerr<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC optimize(2)

inline int Read(void) {
    int res=0,f=1;
    char c;
    while(c=getchar(),c<48||c>57)if(c=='-')f=0;
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>=48&&c<=57);
    return f?res:-res;
}

template<class T>inline bool Min(T &a, T const&b) {
    return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
    return a<b?a=b,1:0;
}
const int N=5e4+5,M=1e5+5,Prime[]= {7,13,17,19};

bool MOP1;

int A[N];

char op[N];

struct SEG {
    int val[5][25][N<<2];
    inline void up(int num) {
        ret(i,0,4)ret(j,0,Prime[i]) {
            int nxt=val[i][j][num<<1];
            val[i][j][num]=val[i][nxt][num<<1|1];
        }
    }
    inline int calc(int a,char op,int b,int mod) {
        if(op=='+')return (a+b)%mod;
        if(op=='*')return (a*b)%mod;
        int res=1;
        while(b) {
            if(b&1)res=res*a%mod;
            a=a*a%mod,b>>=1;
        }
        return res;
    }
    inline void build(int L,int R,int num) {
        if(L==R) {
            rep(i,0,3)ret(j,0,Prime[i])val[i][j][num]=calc(j,op[L],A[L],Prime[i]);
            return;
        }
        int mid=(L+R)>>1;
        build(L,mid,num<<1);
        build(mid+1,R,num<<1|1);
        up(num);
    }
    inline void update(int L,int R,int num,int pos) {
        if(L==R) {
            rep(i,0,3)ret(j,0,Prime[i])val[i][j][num]=calc(j,op[L],A[L],Prime[i]);
            return;
        }
        int mid=(L+R)>>1;
        if(pos<=mid)update(L,mid,num<<1,pos);
        else update(mid+1,R,num<<1|1,pos);
        up(num);
    }
} tr;

int n,res[N],mod[N],a[N],pos[N];

int Exgcd(int a, int b, int &x, int &y) {
    if(!b) {
        x=1,y=0;
        return a;
    }
    int g=Exgcd(b,a%b,y,x);
    y-=a/b*x;
    return g;
}

inline int Excrt(void) {
    mod[1]=7,mod[2]=13,mod[3]=17,mod[4]=19;
    int M=mod[1],ans=res[1],x,y;
    rep(i,2,4) {
        int g=Exgcd(M,mod[i],x,y);
        x*=(res[i]-ans)/g,y=mod[i]/g,x=(x%y+y)%y;
        ans=M*x+ans,M=M/g*mod[i],ans%=M;
    }
    int z=(ans%M+M)%M;
    return z;
}

bool MOP2;

inline void _main(void) {
    int T=Read(),Case=0;
    while(T--) {
        printf("Case #%d:\n",++Case);
        int n,m;
        scanf("%d%d",&n,&m),getchar();
        char c;
        rep(i,1,n)scanf("%c%d",op+i,&A[i]),getchar();
        tr.build(1,n,1);
        while(m--) {
            int Op,pos;
            scanf("%d%d",&Op,&pos);
            if(Op==1) {
                rep(i,0,3)res[i+1]=tr.val[i][pos%Prime[i]][1];
                printf("%d\n",Excrt());
            } else {
                getchar(),scanf("%c%d",op+pos,&A[pos]);
                tr.update(1,n,1,pos);
            }
        }
    }
}

signed main() {
    _main();
    return 0;
}
posted @ 2019-09-23 16:09  dsjkafdsaf  阅读(252)  评论(0编辑  收藏  举报