[bzoj5334] [Tjoi2018] 數學計算
阿新 • • 發佈:2018-11-26
desc namespace 質數 cpp 處理 區別 線段 sample include ;
接下來 \(Q\) 行,每一行為操作類型 \(op\),操作編號或所乘的數字 \(m\)(保證所有的輸入都是合法的).
\(1 \leq Q \leq 100000\)
Description
小豆現在有一個數 \(x\),初始值為 \(1\). 小豆有 \(Q\) 次操作,操作有兩種類型:
1 \(m\): \(x = x \times m\) ,輸出 \(x\)%\(mod\);
2 \(pos\) : \(x = x /\) 第 \(pos\) 次操作所乘的數(保證第 \(pos\) 次操作一定為類型 \(1\),對於每一個類型 \(1\) 的操作至多會被除一次),輸出 \(x\)%\(mod\)
Input
一共有 \(t\) 組輸入( \(t \leq 5\))
對於每一組輸入,第一行是兩個數字 \(Q\), \(mod\) \((Q \leq 100000, mod \leq 1000000000)\)
接下來 \(Q\) 行,每一行為操作類型 \(op\),操作編號或所乘的數字 \(m\)(保證所有的輸入都是合法的).
\(1 \leq Q \leq 100000\)
Output
對於每一個操作,輸出一行,包含操作執行後的 \(x\) % \(mod\) 的值
Sample Input
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7
Sample Output
2
1
2
20
10
1
6
42
504
84
題解
這並不是一道數學題。。。
\(mod\) 不一定是質數所以除掉的數不一定有逆元……
努力將自己思維打開
註意到“每個數至多被刪掉一次”,那相當於每個數只對一段區間裏的答案有貢獻
處理一下每個數被刪除的時間
用線段樹維護所有答案,進行區間修改(乘一個數)或單點查詢。
我的小夥伴們想到了在線做法
線段樹維護當前答案,即每個數對當前答案是否有貢獻
操作1相當於單點修改,詢問相當於區間 \([1,n]\) 求乘積。
我感覺下面這種方法更好想啊,也更好實現,可為啥我想了很久卻想到上面那個奇怪方法啊【捂臉】
區別大概是離線與在線
我本以為此題不能在線,往離線方向想,就要考慮後面的所有答案
而往在線方向想,關註的就僅是當前答案。
代碼
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int N = 100005; typedef long long ll; int P; struct data{ int op,x; }d[N]; int c[N]; struct tree{ int v; tree *ch[2]; }pool[N*2],*root; int cnt; void build(tree *p,int l,int r){ p->v=1; if(l==r) return; int mid=(l+r)>>1; build(p->ch[0]=&pool[++cnt],l,mid); build(p->ch[1]=&pool[++cnt],mid+1,r); } void pushdown(tree *p){ p->ch[0]->v=((ll)p->ch[0]->v*p->v)%P; p->ch[1]->v=((ll)p->ch[1]->v*p->v)%P; p->v=1; } void change(tree *p,int l,int r,int L,int R,int c){ if(l==L && r==R) { p->v=((ll)p->v*c)%P; return; } pushdown(p); int mid=(l+r)>>1; if(R<=mid) change(p->ch[0],l,mid,L,R,c); else if(L>mid) change(p->ch[1],mid+1,r,L,R,c); else { change(p->ch[0],l,mid,L,mid,c); change(p->ch[1],mid+1,r,mid+1,R,c); } } int query(tree *p,int l,int r,int c){ if(l==r) return p->v; pushdown(p); int mid=(l+r)>>1; if(c<=mid) return query(p->ch[0],l,mid,c); return query(p->ch[1],mid+1,r,c); } int main() { int T,Q; scanf("%d",&T); root=&pool[++cnt]; while(T--){ scanf("%d%d",&Q,&P); for(int i=1;i<=Q;i++){ scanf("%d%d",&d[i].op,&d[i].x); if(d[i].op==2) c[d[i].x]=i; } build(root,1,Q); for(int i=1;i<=Q;i++){ if(d[i].op==2) printf("%d\n",query(root,1,Q,i)); else { change(root,1,Q,i,c[i]==0 ? Q : c[i]-1,d[i].x); printf("%d\n",query(root,1,Q,i)); } } //clear for(int i=1;i<=Q;i++) c[i]=0; cnt=1; } return 0; }
[bzoj5334] [Tjoi2018] 數學計算