洛谷 2676 NOIP2015 子串 DP

2021-08-08 20:41:16 字數 1973 閱讀 9628

題目:

個人感覺此題是noip2015最難的一道,本來想爆搜水分,但是子串互不重疊這個條件不會搞,有會搞的請@我,謝謝;

定義方程dp[i][j][k]:a中前i個字元與b中前j個字元匹配,使用了k個子串的方案;

可是存在a[i]是否對答案有貢獻兩種情況;

怎麼辦?

那就加1維記錄,套路……;

若a[i]=b[j]:

a中第i位使用(當且僅當滿足a[i]=b[j])

dp[i][j][k][1]=dp[i-1][j-1][k][1]+dp[i-1][j-1][k-1][0]+dp[i-1][j-1][k-1][1];

即:與i-1相連,不單獨使用 + i-1不使用,i作為新子串 + i-1使用,i作為新子串;

附:方程中的k-1說明i與i-1不組成乙個子串,k說明i與i-1構成第k個子串;

a中第i位不使用(無限制)

dp[i][j][k][0]=dp[i-1][j][k][1]+dp[i-1][j][k][0];

即:將其更新為i-1與j匹配的情況;

可是……1000*200*200*2,會爆記憶體

滾動陣列優化;

我們發現第一維只與i與i-1有關,所以滾動陣列優化掉;

記乙個pre,乙個now;

pre表示前乙個狀態;

now表示當前狀態;

所以在開始新一輪dp時,要初始化pre,並交換pre和now的值;

上乙個狀態的now變為當前狀態的pre;

這樣就成了 2*200*200*2,穩過;

dp[now][1][1][0]=sum(a[1~i-1]==b[j]);

即a前i-1個與b[1]相等的數量;

若a[i]=b[i]

dp[now][1][1][1]=1;

否則 dp[now][1][1][1]=0;

因為當前b中只有乙個字元,所以若a[i]使用,dp陣列最多為1;

正是因為如此,每次要將dp[pre]清空;

做(抄)完這道題,感慨萬千……;

突然發覺dp並沒有想象中的那麼難;

總的套路:

先是狀態的定義(個人認為最關鍵);

然後狀態轉移(用人類的思維);

細節,邊界處理好;

然後就完了;

比如此題:

剛看的時候明知是dp,但就是想打搜尋,這就是所謂未戰先怯吧,

但明白方程和思路後,又覺得沒有想象中的那麼難;

oi征途漫長………………………………………………………………

但是汪國真曾經寫道:」沒有比人更高的山 沒有比腳更長的路 。」

多練習,多總結,多鞏固;

會有收穫的……;

在高二停乙個半月的課,既然付出了代價就讓它付出的有價值吧!

全體參賽oier noip 2017 rp++!

#include

#include

#include

#include

using

namespace

std;

const

int mod=1000000007;

int dp[3][301][301][3],cnt,now,pre=1,n,m,t;

char s1[1021],s2[1021];

void solve()

}for(int j=1;j<=m;j++)

for(int k=1;k<=t;k++)

dp[pre][j][k][1]=dp[pre][j][k][0]=0;

}cout

<<(dp[now][m][t][1]+dp[now][m][t][0])%mod;

return;

}int main()

NOIP2015子串(洛谷2679)

標籤 dp 題目描述 有兩個僅包含小寫英文本母的字串 a 和 b。現在要從字串 a 中取出 k 個互不重疊的非空子串,然後把這 k 個子串按照其在字串 a中出現的順序依次連線起來得到一 個新的字串,請問有多少種方案可以使得這個新串與字串 b 相等?注意 子串取出的位置不同也認為是不同的方案。輸入輸出...

洛谷 2679 NOIP 2015 子串

題目戳這裡 一句話題意 給你兩個字串a,b從a中取出k個不重合子串 順序與在a中順序相同 組成b,問有多少種方案?solution 話說重打還是出各種錯誤也是醉了 先看題目,因為答案與a串,b串和拆分次數都有關,那麼我們把這些都定義進dp方程中 定義f i j k 0 代表選到a串的前i個字元中選k...

洛谷P2679 NOIP2015 子串

無 有兩個僅包含小寫英文本母的字串 a 和 b。現在要從字串 a 中取出 k 個互不重疊的非空子串,然後把這 k 個子串按照其在字串 a 中出現的順序依次連線起來得到一 個新的字串,請問有多少種方案可以使得這個新串與字串 b 相等?注意 子串取出 的位置不同也認為是不同的方案。輸入格式 輸入檔名為 ...