2020.03.21日常總結——思維題與全面的思考

思維題——洛谷P4588     [TJOI2018]數學計算\color{green}{\text{思維題——洛谷P4588\ \ \ \ \ [TJOI2018]數學計算}}

【題目】:\color{blue}{\text{【題目】:}} 你有一個數 xx,初始爲 11。你有兩種操作,分別爲:

    1. 給定一個數 mm,把 xx 變成 x×mx \times m,然後輸出 xxmod\text{mod} 取模的值。
    1. 給定一個數 tt,把 xx 變爲 x/x/tt 次操作所乘的數。如第 tt 次操作所乘數爲 22,則把 xx 變爲 x2\dfrac{x}{2}。數據保證第 tt 次操作一定是操作 11,且每個操作最多被除一次,即保證 xx 在任何時候都是一個整數。操作後,輸出 xxmod\text{mod} 取模的值。

【思路】:\color{blue}{\text{【思路】:}} 直接模擬會因爲爆 long long 的問題導致代碼非常複雜,甚至無法編寫。

考慮強大的數據結構——線段樹。建立一棵線段樹,其葉子節點都是對於的乘數,每個非葉子節點的值爲其左右兒子的值的乘積對 mod\text{mod} 取模的值。這樣,任意時候都有 x=x= 該線段樹的根的值。

操作 11 可以直接上,操作 22 可以看做是把第 tt 次的乘數改爲 11。因此,我們只需要打一個線段樹修改即可。

\color{blue}{【代碼】:}

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;
}

洛谷P1575     正誤問題\color{green}{\text{洛谷P1575\ \ \ \ \ 正誤問題}}

\color{blue}{【鏈接】:} https://www.luogu.com.cn/problem/P1575

\color{blue}{【思路】:} 很簡單,直接用一個棧模擬即可。如果 not 後面不是 truefalse 的話,就輸出 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 了嗎?不是,有 11 個點錯了。爲什麼?

因爲數據中有如這樣的情況 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章