NOIp提高組/CSP-S 2019 Day1 試做
阿新 • • 發佈:2020-08-15
NOIp提高組/CSP-S 2019 DAY1 試做
按學長說的,刷一刷 NOIp 的題,然後就從洛谷裡直接找到了2019年的題,按順序先刷DAY1的,結果做到一半才想起來,去年的題好像不大對勁,嚴格說應該是CSP-S 2019……算了都已經開始了,至少把 D1 的先做了吧……
D1T1 格雷碼
題目描述
下方傳送門
題目連結
上方傳送門
思路分析
- zz找規律題,硬是傻眼了半天。
- 還是得先好好讀題。對於每次我們得出的格雷碼,都可以分兩半組成,前一半都是 \(0\) 開頭的,而後一半都是 \(1\) 開頭的。以這個規律為突破口。
- 列舉一下 \(n=4\) 時的答案,大概是這樣的
0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000
- 這樣就不難想到將格雷碼分而治之(即分治),依循上面的規律已經得出第一位,那麼第二位發現稍微有了一些變化。發現如果我們從後半段進行分治的話,規律正好反了過來,但其實大同小異
- 雖然是D1T1,但做起來並沒想象中的輕鬆,後來大致掃了一下題解,好像沒幾個我這麼做的,都是一些奇奇怪怪的規律。
- 另外求平方時別用左移別用左移!!!因為最高只能左移32位,就這破東西卡了我半個小時改來改去,然後我輸出了一下1<<43的結果發現事情不大對勁。
Code
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define ll unsigned long long //2^64 long long會炸 using namespace std; inline ll read(){ ll x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } ll n,k; int main(){ n = read(),k = read(); bool flag = 1; //flag標記是否需要倒轉規律 ll res = pow(2,n-1); while(res){ if(k>=res){ flag?putchar('1'),flag=0:putchar('0'); k-=res; } else flag?putchar('0'):putchar('1'),flag=1; res>>=1; } return 0; }
D1T2 括號樹
下方傳送門
題目連結
上方傳送門
思路分析
- 這個沒啥可說的……括號匹配當然要想到壓棧彈棧,只是放樹上了,並無大礙
- 個人感覺T1比這題坑……
詳見程式碼
Code
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define N 500010 #define int long long using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,fa[N],head[N],sum[N],pre[N],sta[N],top; char s[N]; struct edge{ int to,next; }e[N]; int len; void addedge(int u,int v){ e[++len].to = v; e[len].next = head[u]; head[u] = len; } void dfs(int u){ int res = 0; if(s[u]=='(')sta[++top] = u; //壓進棧裡等待匹配 else{ //遇到')'就可以從棧裡拿出括號來匹配了 if(top){ res = sta[top]; pre[u] = pre[fa[res]]+1; //再左括號的父親的基礎上又增加了1對 top--; } } sum[u] = sum[fa[u]]+pre[u]; for(int i = head[u];i;i=e[i].next){ int v = e[i].to; dfs(v); } if(res)sta[++top] = res; //記得再放回去,不然你會像我一樣獲得85分的好成績 else if(top)top--; //要是未從棧內拿出元素且壓入了一個左括號,遞迴完了就需要彈出去,因為前面的點用不到 } signed main(){ n = read(); scanf("%s",s+1); for(int i = 2;i <= n;i++){ fa[i] = read(); addedge(fa[i],i); } dfs(1); int ans = 0; for(int i = 1;i <= n;i++)ans ^= i*sum[i]; printf("%lld\n",ans); return 0; }
D1T3
下方傳送門
題目連結
上方傳送門
- 這tm是道黑題???看了看題,目測只會打10分暴力,做個球,咕了咕了。
總結
- T1 題目那麼長看著挺唬人的,而且乍一眼看上去也沒什麼思路,這時候還是反覆讀讀題,找一找規律
- T2 思路很簡單但還是有些細節要處理的,
比如我的85分 - 這年的題不是很“正宗”,所以D2可能會咕掉,而轉去做其他年份的題