你有一個數 ,初始爲 。你有兩種操作,分別爲:
-
- 給定一個數 ,把 變成 ,然後輸出 對 取模的值。
-
- 給定一個數 ,把 變爲 第 次操作所乘的數。如第 次操作所乘數爲 ,則把 變爲 。數據保證第 次操作一定是操作 ,且每個操作最多被除一次,即保證 在任何時候都是一個整數。操作後,輸出 對 取模的值。
直接模擬會因爲爆 long long
的問題導致代碼非常複雜,甚至無法編寫。
考慮強大的數據結構——線段樹。建立一棵線段樹,其葉子節點都是對於的乘數,每個非葉子節點的值爲其左右兒子的值的乘積對 取模的值。這樣,任意時候都有 該線段樹的根的值。
操作 可以直接上,操作 可以看做是把第 次的乘數改爲 。因此,我們只需要打一個線段樹修改即可。
const int N=1e5+100;
#define ll long long
ll mod;int tot,G[N];
int test_number,q;
struct Segment_tree{
ll sum[N<<2];//記得4倍空間
inline void pushup(int o){
sum[o]=sum[o<<1]*sum[o<<1|1]%mod;
}
inline void build(int o,int l,int r){
if (l==r){sum[o]=1ll;return;}
register int mid=(l+r)>>1;
build(o<<1|1,mid+1,r);
build(o<<1,l,mid);
pushup(o);return;
}
void updata(int o,int l,int r,int p,ll v){
if (l==r){sum[o]=v;return;}
register int mid=(l+r)>>1;
if (p<=mid) updata(o<<1,l,mid,p,v);
else updata(o<<1|1,mid+1,r,p,v);
pushup(o);return;
}
}SGT;
#define gc getchar()
#define g(c) isdigit(c)
inline ll read(){
char c=0;ll x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
namespace fast_write{
void write(ll a,bool b){
if (a==0){
if (b) putchar('0');
}
else{
write(a/10,false);
putchar(a%10+'0');
}
}
void print(ll a,char c){
write(a,true);
putchar(c);
}
}
int main(){
test_number=read();
while (test_number--){
q=read();mod=read();
SGT.build(1,1,q);tot=0;
memset(G,0,sizeof(G));
for(int i=1;i<=q;i++){
int opt=read();ll t=read();
if (opt==2) SGT.updata(1,1,q,G[t],1);
else SGT.updata(1,1,q,G[i]=(++tot),t%mod);
fast_write::print(SGT.sum[1]%mod,'\n');
}
}
return 0;
}
https://www.luogu.com.cn/problem/P1575
很簡單,直接用一個棧模擬即可。如果 not
後面不是 true
或 false
的話,就輸出 error
。
#include <bits/stdc++.h>
using namespace std;
stack<bool> num;
stack<string> oper;
int cti(string s){
if (s=="or") return 1;
if (s=="and") return 2;
if (s=="not") return 3;
return 0;
}
inline bool calc(){
register bool x,y;
if (num.size()){
y=num.top();num.pop();
}
else return false;
if (num.size()){
x=num.top();num.pop();
}
else return false;
string c=oper.top();oper.pop();
if (c=="and") num.push(x&&y);
else num.push(x||y);
return true;
}
bool Not(string s){
if (s=="true") return 0;
if (s=="false") return 1;
}
string s;bool flag;
int main(){
getline(cin,s);
stringstream ss(s);
while (ss>>s){
if (s=="not"){
if (ss>>s){
if (s!="true"&&s!="false"){
printf("error");
return 0;
}
else num.push(Not(s));
}
else{
printf("error");
return 0;
}
flag=false;
}
else if (cti(s)){
if (num.empty()){
printf("error");
return 0;
}
while (oper.size()&&cti(oper.top())>=cti(s)){
if (!calc()){
printf("error");
return 0;
}
}
oper.push(s);
flag=false;
}
else{
if (flag){
printf("error");
return 0;
}
num.push(!Not(s));
flag=true;
}
}
while (oper.size()){
if (!calc()){
printf("error");
return 0;
}
}
if (num.size()!=1){
printf("error");
return 0;
}
if (num.top()) printf("true");
else printf("false");
return 0;
}
可是,這樣真的就 AC
了嗎?不是,有 個點錯了。爲什麼?
因爲數據中有如這樣的情況 not not true
,這種情況下我們的程序會輸出 error
,但是它實際上是應該輸出 true
的。我們特殊處理即可。
#include <bits/stdc++.h>
using namespace std;
stack<bool> num;
stack<string> oper;
int cti(string s){
if (s=="or") return 1;
if (s=="and") return 2;
if (s=="not") return 3;
return 0;
}
inline bool calc(){
register bool x,y;
if (num.size()){
y=num.top();num.pop();
}
else return false;
if (num.size()){
x=num.top();num.pop();
}
else return false;
string c=oper.top();oper.pop();
if (c=="and") num.push(x&&y);
else num.push(x||y);
return true;
}
inline bool Not(string s){
if (s=="true") return 0;
else return 1;
}
string s;bool flag,sign;
int main(){
getline(cin,s);
stringstream ss(s);
while (ss>>s){
if (s=="not"){
if (ss>>s){
if (s!="true"&&s!="false"&&s!="not"){
printf("error");
return 0;
}
if (s=="true"||s=="false")
num.push(Not(s));
else{
sign=false;
while (ss>>s){
if (s!="true"&&s!="false"&&s!="not"){
printf("error");
return 0;
}
else{
if (s=="not") sign=!sign;
else{
num.push(sign?Not(s):!Not(s));
break;
}
}
}
}
}
else{
printf("error");
return 0;
}
flag=false;
}
else if (cti(s)){
if (num.empty()){
printf("error");
return 0;
}
while (oper.size()&&cti(oper.top())>=cti(s)){
if (!calc()){
printf("error");
return 0;
}
}
oper.push(s);
flag=false;
}
else{
if (flag){
printf("error");
return 0;
}
num.push(!Not(s));
flag=true;
}
}
while (oper.size()){
if (!calc()){
printf("error");
return 0;
}
}
if (num.size()!=1){
printf("error");
return 0;
}
if (num.top()) printf("true");
else printf("false");
return 0;
}
/*
注意!需要特殊判斷如not not true這樣的情況,
否則無法通過第七個測試點
*/
這提示我們,只有全面的思考,才能獲得高分或者 AC
!