1259 整數劃分 v2
題面比較直白, 不解釋
這個整數劃分和dp的入門題的整數劃分有不同,就是資料範圍, 這個資料範圍是5w, o(n^2)肯定不行.
這裡的方法是我們想象: 把n的劃分分為兩個部分: 成分為**[1, 根號n], 另一部分是[(根號n) + 1, n]**.
比如n = 4: 4的開方為2; 那麼我們對於, 這個劃分, 就是由, 組成的,那麼我們發現, 如果我們考慮小於根號n的這個部分, 我們可以設定狀態dp[ n ] [根號n], 那麼dp[i] [j]就表示為總和為i, 其中的最大的劃分成分為j時候的可行的劃分種數: 這個與入門題的整數劃分思想一致,可以通過兩次遍歷求出這個陣列中的所有值
那麼對於第二部分:即每乙個成分都大於根號n, 我們不難看出, 如果對於乙個數i, 劃分的結果中最小的成分不小於"(根號n)+1",那麼每乙個劃分的組成元素的數量不會超過根號n, 想象總和為10000, 根號n就是100, 那麼100個100就可以組成10000, 所以成分最多不會超過根號n個, 那麼我們就可以把成分的數量設為dp的狀態 dp1[ n ] [根號n] , 那麼dp1[i] [j]表示總和為i, 由j個成分比根號n大的元素組成的劃分的數量, 這個轉移就可以考慮為: 假設當前dp1[sum] [j], 那麼我要求最小的元素必須不小於"(根號n)+1", 所以 ①由dp1[sum- 根號n - 1] [j - 1]可以得到, 這個轉移的原理就是我在dp1[sum- 根號n - 1] [j - 1]的所有劃分上加乙個單獨的元素-------"(根號n)+1" ②由dp1[sum- j] [j]得到, 原理就是我在dp1[sum- j] [j]的所有劃分上對於每乙個元組的值都加上"1", 也是符合題意的.
#include
using namespace std;
typedef
long
long ll;
const
int maxn =
5e4+60;
const
int mod =
1e9+7;
//全部由m以及它以下的成分組成
ll dp1[maxn]
;//全部由m以上的成分組成
ll dp2[maxn]
[250];
ll sum[maxn]
;void
solve()
}
dp2[0]
[0]=
1;//sum表示用大於(根號n)+1 的元素組成的總的方案數
sum[0]
=1;//注意tot的起始值
for(
int tot = m +
1; tot <= n;tot++)}
ll ans =0;
for(
int i =
0; i <= n; i++
) cout<}int
main()
51Nod 1259 整數劃分 V2
將n分為若干個整數的和,有多少種不同的劃分方式,例如 n 4,共5種。由於資料較大,輸出mod 10 9 7的結果即可。input 輸入1個數n 1 n 50000 output 輸出劃分的數量mod 10 9 7。input示例 output示例 分塊dp 複雜度o n sqrt n 設m sqr...
51nod 1259 整數劃分 V2(分塊dp)
題目 將n分為若干個整數的和,有多少種不同的劃分方式,例如 n 4,共5種。由於資料較大,輸出mod 10 9 7的結果即可。輸入輸入1個數n 1 n 50000 輸出輸出劃分的數量mod 10 9 7。輸入樣例 輸出樣例 題解分塊dp 複雜度o n sqrt n 設m sqrt n 我們可以先考慮...
51nod 1128 正整數分組 V2
給出乙個長度為n的正整數陣列,不改變陣列元素的順序,將這n個數分為k組。各組中元素的和分別為s1,s2 sk。如何分組,使得s1至sk中的最大值最小?例如 1 2 3 4 5 6分為3組,元素和為6,9,6,最大值為9。也可以分為 元素和為 10 5 6,最大值為10。因此第一種方案更優。並且第一種...