题目描述
给定一个关于 (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),我们有:
[egin{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:
",++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
",Excrt());
} else {
getchar(),scanf("%c%d",op+pos,&A[pos]);
tr.update(1,n,1,pos);
}
}
}
}
signed main() {
_main();
return 0;
}