題目:
個人感覺此題是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 相等?注意 子串取出 的位置不同也認為是不同的方案。輸入格式 輸入檔名為 ...