1. 程式人生 > 其它 >Codeforces 730L - Expression Queries(大模擬)

Codeforces 730L - Expression Queries(大模擬)

大模擬,阿巴細節題

Codeforces 題面傳送門 & 洛谷題面傳送門

大模擬(?)+阿巴細節題,模擬賽時剛了 3h 最後因為某個細節寫掛 100->40/ll/ll(下次一定不能再掛分了啊 awa)

首先先考慮怎麼判 \(-1\),顯然如果區間 \([l,r]\) 中間的括號構不成合法的括號序列,答案顯然是 \(-1\),其次如果 \(s_l\) 是加號或乘號那算式也不合法,\(s_r\) 也同理,這可以通過字首和+ST 表在 \(\mathcal O(n\log n)-\mathcal O(1)\) 時間內判斷。

其次考慮怎樣計算一個表示式的值,首先按照套路建出表示式樹,不過這裡建表示式樹與平常略微有點不同,平常我們建的表示式樹都是二叉樹,即將運算子放在中間,參與運算的兩個部分作為該節點的左右兒子,這次咱們偏不建二叉樹,咱們建多叉樹,具體來說,對於同一個括號內的統計運算我們同時將它們設為該運算代表的節點的兒子(比方說 \(1+2\times 3+4\times 5\)

的根節點就有 \(3\) 個兒子 \(1,2\times 3,4\times 5\),中間運算子為加號),我們同時記錄這些兒子執行的運算在原字串中對於的區間,比方說 \(2\times 3\) 這個兒子在原字串中的區間就是 \([3,5]\)

那麼對於一個詢問而言,如果它本身就是一個數(比方說 \(1234\)\((((7)))\))那麼我們就直接輸出這個數即可,否則我們找出計算這個表示式時最後一次執行的運算表示的節點 \(x\),顯然 \(x\) 表示的運算有加號或乘號兩種可能,分情況討論:

首先考慮乘法,我們假設 \(x\) 的兒子在原字串中的區間分別為 \([a_1,b_1],[a_2,b_2],\cdots,[a_m,b_m]\)

,那麼我們二分找出 \(l,r\) 所在的區間,假設為 \([a_L,b_L]\)\([a_R,b_R]\),顯然這些區間在 \([l,r]\) 中的部分是一個個整段+邊上兩個散塊,中間部分對答案的貢獻顯然是完整的,直接字首積即可 \(\mathcal O(1)\) 求出,注意特判字首積為 \(0\) 的情況,此時需記錄字首 \(0\) 的個數加以判斷,對於邊上兩塊的情況分情況討論:有可能兩邊也是整塊貢獻,這時候直接計入答案即可,也有可能兩邊是某一段數計入貢獻(比方說 \(12\times 34\times 56\),對於詢問 \([2,7]\) 而言,左邊的 \(12\) 和右邊的 \(56\)
就分別被一分為二),此時寫一個類似雜湊的東西快速求出一段區間表示的數即可在常數時間內累加貢獻。

接下來考慮加法,和乘法類似,我們還是找出 \(l,r\) 所在的區間 \([a_L,b_L]\)\([a_R,b_R]\),這些區間在 \([l,r]\) 中的部分還是一個個整段+邊上兩個散塊,對於中間部分對字首和搞一下即可,對於邊上兩塊的情況還是分情況討論:前兩類(整塊貢獻&某個數一分為二)與乘法一樣不再贅述,但是加法比乘法多的一種情況是,有可能邊角塊對應的運算是一個序列的乘法運算(比方說 \(12\times 34+56\times 78\) 對於詢問 \([2,10]\) 而言,左邊區間計入貢獻的部分就是 \(2\times 34\),右邊部分也同理),以左邊的散塊為例,這種情況就找到 \([a_L,b_L]\) 對應的節點,二分一下乘法對應的區間(顯然是一段字尾),然後還是字首積算一算即可,注意,在這部分裡的乘法操作中還是有可能出現某個數一分為二的情況,注意判斷。

時間複雜度 \(n\log n\),注意特判一些奇奇怪怪的情況,比方說 \(((((((1145141919810))))))\) 或者 \((998244353)\times (19260817)\),我就是因為這邊有個細節寫掛了而丟了 60pts/ll

程式碼(碼了 238 行,現以吊打切樹遊戲、吊打 CF788E,榮膺我 AC 的題目中的碼量之最)

const int MAXN=5e5;
const int LOG_N=20;
const int MOD=1e9+7;
int qpow(int x,int e){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
	return ret;
}
int n,qu,ncnt,sum[MAXN+5],dep[MAXN+5];char s[MAXN+5];
int nt[MAXN+5],pr[MAXN+5];
vector<int> son[MAXN+5];
vector<pii> itvl[MAXN+5];
int mch[MAXN+5],rt,bel[MAXN+5],op[MAXN+5],val[MAXN+5];
int pre[MAXN+5],pw10[MAXN+5];
int getnum(int l,int r){return (pre[r]-1ll*pre[l-1]*pw10[r-l+1]%MOD+MOD)%MOD;}
int build(int l,int r){
	if(s[l]=='('&&mch[l]==r) return bel[l]=bel[r]=build(l+1,r-1);
	int opt=-1,id=++ncnt;
	for(int i=l;i<=r;){
		if(s[i]=='+') opt=0;
		else if(s[i]=='*'&&!~opt) opt=1;
		if(s[i]=='(') i=mch[i]+1;
		else i++;
	} op[id]=opt;
	if(!~opt){
		for(int i=l;i<=r;i++){
			bel[i]=id;
			val[id]=(10ll*val[id]+s[i]-'0')%MOD;
		} return id;
	} int pre=l-1;
	for(int i=l;i<=r;){
		if((s[i]=='+'&&!opt)||(s[i]=='*'&&opt)){
			son[id].pb(build(pre+1,i-1));
			itvl[id].pb(mp(pre+1,i-1));
			pre=i;bel[i]=id;
		} if(s[i]=='(') i=mch[i]+1;
		else i++;
	} son[id].pb(build(pre+1,r));itvl[id].pb(mp(pre+1,r));
//	printf("build [%d,%d]:\n",l,r);
//	printf("op[%d]=%d\n",id,op[id]);
//	for(int x:son[id]) printf("%d ",x);printf("\n");
//	for(pii p:itvl[id]) printf("[%d,%d]\n",p.fi,p.se);
//	printf("\n");
	return id;
}
struct num0{
	int x,y;
	num0(int _x=0){(_x)?(x=_x,y=0):(x=y=1);}
	int val(){return (y)?0:x;}
	num0 operator +(const int &rhs){
		int sum=(val()+rhs)%MOD;
		return (sum)?num0(sum):num0(0);
	}
	num0 operator *(const int &rhs){
		num0 res=*this;
		(rhs)?(res.x=1ll*res.x*rhs%MOD):(res.y++);
		return res;
	}
	num0 operator /(const num0 &rhs){
		num0 res;res.x=1ll*x*qpow(rhs.x,MOD-2)%MOD;
		res.y=y-rhs.y;return res;
	}
};
vector<num0> ss[MAXN+5];
void calc(int x){
	if(~op[x]) val[x]=op[x];
	ss[x].resize(son[x].size());
	for(int i=0;i<son[x].size();i++){
		int y=son[x][i];dep[y]=dep[x]+1;calc(y);
		if(!i) ss[x][i]=val[y];
		if(op[x]==0){
			val[x]=(val[x]+val[y])%MOD;
			if(i) ss[x][i]=ss[x][i-1]+val[y];
		} else {
			val[x]=1ll*val[x]*val[y]%MOD;
			if(i) ss[x][i]=ss[x][i-1]*val[y];
		}
//		printf("%d %d %d\n",x,i,ss[x][i].val());
	}
}
int st_sum[MAXN+5][LOG_N+2];
pii st_dep[MAXN+5][LOG_N+2];
void buildst(){
	for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n;j++){
		st_sum[j][i]=min(st_sum[j][i-1],st_sum[j+(1<<i-1)][i-1]);
		st_dep[j][i]=min(st_dep[j][i-1],st_dep[j+(1<<i-1)][i-1]);
	}
}
int query_sum(int l,int r){
	int k=31-__builtin_clz(r-l+1);
	return min(st_sum[l][k],st_sum[r-(1<<k)+1][k]);
}
pii query_dep(int l,int r){
	int k=31-__builtin_clz(r-l+1);
	return min(st_dep[l][k],st_dep[r-(1<<k)+1][k]);
}
int main(){
//	freopen("calc.in","r",stdin);
//	freopen("calc.out","w",stdout);
	scanf("%s%d",s+1,&qu);n=strlen(s+1);
	for(int i=1;i<=n;i++){
		if(isdigit(s[i])) pre[i]=(10ll*pre[i-1]+s[i]-'0')%MOD;
		else pre[i]=pre[i-1];
	}
	for(int i=(pw10[0]=1);i<=n;i++) pw10[i]=10ll*pw10[i-1]%MOD;
	stack<int> stk;
	for(int i=1;i<=n;i++){
		if(s[i]=='(') stk.push(i),sum[i]=sum[i-1]+1;
		else if(s[i]==')'){
			mch[i]=stk.top();mch[stk.top()]=i;
			stk.pop();sum[i]=sum[i-1]-1;
		} else sum[i]=sum[i-1];
	}
	int pp=n+1;
	for(int i=n;i;i--){
		if(!isdigit(s[i])) pp=i;
		else nt[i]=pp-1;
	} pp=0;
	for(int i=1;i<=n;i++){
		if(!isdigit(s[i])) pp=i;
		else pr[i]=pp+1;
	}
//	for(int i=1;i<=n;i++) printf("%d%c",mch[i]," \n"[i==n]);
	rt=build(1,n);calc(rt);
//	for(int i=1;i<=n;i++) printf("%d%c",bel[i]," \n"[i==n]);
	for(int i=1;i<=n;i++) st_sum[i][0]=sum[i],st_dep[i][0]=mp(dep[bel[i]],i);
	buildst();
	while(qu--){
		int l,r;scanf("%d%d",&l,&r);
		if(sum[l-1]!=sum[r]){puts("-1");continue;}
		if(query_sum(l,r)<sum[l-1]){puts("-1");continue;}
		if(s[l]=='+'||s[l]=='*'){puts("-1");continue;}
		if(s[r]=='+'||s[r]=='*'){puts("-1");continue;}
		pii p=query_dep(l,r);int x=bel[p.se];
//		printf("%d\n",x);
		if(!~op[x]){
			if(isdigit(s[l])&&isdigit(s[r])) printf("%d\n",getnum(l,r));
			else printf("%d\n",val[x]);
			continue;
		}
		int L=upper_bound(itvl[x].begin(),itvl[x].end(),mp(l,n+1))-itvl[x].begin()-1;
		int R=upper_bound(itvl[x].begin(),itvl[x].end(),mp(r,n+1))-itvl[x].begin()-1;
		if(L<0) L=0;
		int u=son[x][L],v=son[x][R];
//		printf("%d %d\n",L,R);
		if(op[x]==1){
			int res=1;
			if(L!=R){
				num0 qwq=ss[x][R-1]/ss[x][L];
				res=qwq.val();
			}
			if(~op[u]) res=1ll*res*val[u]%MOD;
			else{
				if(isdigit(s[l])) res=1ll*res*getnum(l,nt[l])%MOD;
				else res=1ll*res*val[u]%MOD;
			} if(~op[v]) res=1ll*res*val[v]%MOD;
			else{
				if(isdigit(s[r])) res=1ll*res*getnum(pr[r],r)%MOD;
				else res=1ll*res*val[v]%MOD;
			}
			printf("%d\n",res);
		} else {
			int res=0;
			if(L!=R) res=(ss[x][R-1].val()-ss[x][L].val()+MOD)%MOD;
			if(~op[u]){
				if(op[u]==0) res=(res+val[u])%MOD;
				else{
					int LL=upper_bound(itvl[u].begin(),itvl[u].end(),mp(l,n+1))-itvl[u].begin()-1;
					if(LL<0) LL=0;
					int su=son[u][LL],mul=1;
					if(LL+1!=ss[u].size())
						mul=(ss[u].back()/ss[u][LL]).val();
					if(~op[su]) mul=1ll*mul*val[su]%MOD;
					else{
						if(isdigit(s[l])) mul=1ll*mul*getnum(l,nt[l])%MOD;
						else mul=1ll*mul*val[su]%MOD;
					}
					res=(res+mul)%MOD;
				}
			} else{
				if(isdigit(s[l])) res=(res+getnum(l,nt[l]))%MOD;
				else res=(res+val[u])%MOD;
			}
			if(~op[v]){
				if(op[v]==0) res=(res+val[v])%MOD;
				else{
					int RR=upper_bound(itvl[v].begin(),itvl[v].end(),mp(r,n+1))-itvl[v].begin()-1;
					int sv=son[v][RR],mul=1;
					if(RR) mul=(ss[v][RR-1]).val();
					if(~op[sv]) mul=1ll*mul*val[sv]%MOD;
					else{
						if(isdigit(s[r])) mul=1ll*mul*getnum(pr[r],r)%MOD;
						else mul=1ll*mul*val[sv]%MOD;
					}
					res=(res+mul)%MOD;
				}
			} else{
				if(isdigit(s[r])) res=(res+getnum(pr[r],r))%MOD;
				else res=(res+val[v])%MOD;
			}
			printf("%d\n",res);
		}
	}
	return 0;
}