題目描述
摺疊的定義如下:
乙個字串可以看成它自身的摺疊。記作s = s
x(s)是x(x>1)個s連線在一起的串的摺疊。記作x(s) = ssss…s(x個s)。
如果a = a』, b = b』,則ab = a』b』 例如,因為3(a) = aaa, 2(b) = bb,所以3(a)c2(b) = aaacbb,而2(3(a)c)2(b) = aaacaaacbb
給乙個字串,求它的最短摺疊。例如aaaaaaaaaabababccd的最短摺疊為:9(a)3(ab)ccd。
輸入格式
僅一行,即字串s,長度保證不超過100。
輸出格式
僅一行,即最短的摺疊長度。
輸入輸出樣例
輸入neercyesyesyesneercyesyesyes
輸出14
說明/提示
乙個最短的摺疊為:2(neerc3(yes))
看完題目和資料範圍,很容易想到這是一道區間dp,即設f[i
][j]
f[i][j]
f[i][j
]表示合併字串第i
ii位到第j
jj位過後的最小長度,那麼該如何轉移這個狀態?
首先講一下我最開始的思路:用乙個陣列min
n[i]
[j
]minn[i][j]
minn[i
][j]
把每乙個狀態得到的字串分別存起來,然後在暴力列舉區間判斷是否相等,但是這種做法會非常麻煩,並且還會超時,因為我們存的是每乙個狀態的字串,不好判斷兩個區間的迴圈節是否相等,所以明顯不行,那麼就再考慮用乙個陣列m[i
][j]
m[i][j]
m[i][j
]把每一種狀態的迴圈節也存下來同時用乙個陣列cir
[i][
j]
cir[i][j]
cir[i]
[j]把每個迴圈節前的係數存下來,這樣就可以省去一層判斷迴圈節是否相等的迴圈.
那麼就可以得出狀態轉移方程
f_=\min(f_+2+(cir_+cir_)的位數),l\le k < r,m_=m_\\f_=\min(f_+f_),l\le k
return res;
}string cov
(int n)
//將乙個數變為字串
reverse
(res.
begin()
, res.
end())
;return res +
"(";
}void
work
(int l,
int k,
int r)
} string temp = minn[l]
[k]+ minn[k +1]
[r];
//另一種情況
if(temp.
length()
< m[l]
[r].
length()
|| m[l]
[r]=="")
//直接合併得到的迴圈節更優
if(temp.
length()
< f[l]
[r])
//轉移狀態
}int
main()
//以上為初始化
for(
int len =
2; len <= n;len++)}
cout << minn[1]
[n]<< endl;
//輸出答案
}return0;
}
UVA 1630 記憶化搜尋
輸入乙個字串,摺疊成乙個盡量短的串。問最短可以摺疊成什麼樣子的乙個串。設dp i j 為字串i到j摺疊成最短的字串後的長度,ss i j 為字串i到j摺疊成的最短的字串。dfs 記憶化搜尋即可。輸入的字串右邊界為str.size 1,需要特別注意。include include include in...
題解 P1630 求和
題目 發現題解都不夠優雅,就自己來一篇 首先,看清楚了,題目是 sum ai b 的餘數 而不是 sum ab i 等比數列求和了解一下 畢竟.本蒟蒻一開始就看錯了.好,進入正題,介於 a,b leq 10 9 暴力就想都不用想了,肯定過不了每一次乘法需要 o b 的時間,加法需要 o a 的時間,...
UVA1630 Folding 區間動態規劃
摺疊乙個字串,使得其成為乙個盡量短的字串 例如aaaaaa變成6 a 而且這個摺疊是可以巢狀的,例如 neeeeeryesyesyesneeeeeryesyesyes 會變成 2 n5 e r3 yes 用dp i j 表示i j壓縮的最小長度dp i j min dp i j dp i k dp ...