原因是我在考場上想出了正解卻沒調出來。。。
題目鏈結
題面讓你求一棵樹上能匹配的括號串的個數。
呃,前面的20分直接暴力過(在加上是鏈隨便打一下就好了啦),我就不解釋了(明明是沒寫然後又不想寫)。
然後說一下由於考場上沒調出來而交的55分**吧。
首先先來看一下鏈的性質。
明顯的一件事,形如 (()
)(\ (\ )\ )
(())
這樣的鏈,如果要把外層的括號匹配上,顯然前提是你在這裡面的所有括號能恰好匹配完而且你全部選上了,那麼其實就是說你可以把每一層的括號分開算,它們對答案的貢獻是互不影響的,那麼就可以每層分開算。
然後再看看形如 ()(
)(
)(\ )\ (\ )\ (\ )
()()()
這樣的鏈,它對答案的貢獻為 3+2
+1
3+2+1
3+2+
1 個(選1對括號,2對括號,3對括號能對答案做出的貢獻),所以相當於當前層中,你每多加上一對括號,就對答案產生包括當前括號在內的,當前層已經匹配上的括號對數。
然後如果你發現最外面的那一層如果掃到乙個右括號沒有左括號可以來和它匹配,那麼就相當於把這個鏈分成了兩個互不相干的鏈,那麼接下來再重新開始統計匹配。
所以。。。
讀入資料後,由於題目給的是保證它的父節點是比它編號小一的,那麼就可以直接乙個 o(n
)o(n)
o(n)
的for迴圈搜下去,用 ktkt
kt表示當前所在層數,ksks
ks表示當前層已匹配的括號數,每當要傳到下一層的時候,就把 ksks
ks傳到 cs[
kt
]cs[kt]
cs[kt]
裡儲存,等退回來的時候再用。然後再用乙個 tmp
tmptm
p 記錄目前的答案,再用最後要輸出的 ans
ansan
s 異或上當前的 tmp
∗i
tmp*i
tmp∗
i。最後輸出即可。
主要**:
for
(int i=0;
++i<=n;
)else
if(kt>0)
else ks=kt=0;
tmp+
=ks;
ans^
=(tmp*i)
;}
進正解
其實你想出了鏈的思路,那麼你離正解也不遠了。。。
顯然我們可以用dfs把鏈擴充套件到樹上,再改一改轉移的東西,然後就可以過了。。。
正解**(上文是考試時候本來想拿來對拍的程式,下文是後來重新敲的,變數名沒對上勿噴):
#include
using
namespace std;
const
int n=
5e5+10;
int n,ans=
0,top[n]
,f;long
long tot=
0,sum[n<<1]
,num[n]
;char a[n]
;struct lol e[n]
;void
freo()
void
ein(
int x,
int y)
; top[x]
=ans;
}int
dfs(
int x,
int fa,
int cnt,
long
long tmp)
void
init()
void
work()
void
prin()
intmain()
題解 括號染色
petya遇到了乙個關於括號序列的問題 給定乙個字串s,它代表著正確的括號序列,即 與 是匹配的。例如 和 是正確的,與 則不是正確的。在正確的括號序列中,乙個左邊的括號一定是匹配乙個右邊的括號 反之亦然 例如,在下圖中,第 3 個括號匹配第 6 個括號,第 4 個括號匹配第 5 個括號。現在你需要...
題解 括號匹配
題解 描述假設表示式中只包含三種括號 圓括號 方括號和花括號,它們可相互巢狀,如 或 等均為正確的格式,而 或均為不正確的格式.輸入一串括號 如果輸入的右括號多餘,輸出 extra right brackets 如果輸入的左括號多餘,輸出 extra left brackets 如果輸入的括號不匹配...
防線 s 題解
題面 乙個一維區間上,從s i s i s i 到e i e i e i 這段上每隔d i d i d i 的距離放乙個防具 s i s i s i 必須放,e i e i e i 不一定要放 執行n nn組,問是否存在乙個點上有奇數個防具 資料保證最多只有乙個點上為奇數個 暴力列舉?想多了吧,就憑...