難度中等
a:二進位制拆分 + 01揹包;
n可以拆分為 1、2、4 …… 2 ^ (k - 1)、n - 2 ^ k + 1
m = 100000,複雜度是 mnlogn,不知道為啥能過……
b:完全揹包,滾動陣列優化;
c:01揹包;
d:乙個包裝的01揹包問題,將錢數看作價值,**的概率看作體積,但是注意概率不能靠加減法計算,而是乘除法;
考慮到陣列下標不能是小數,所以讓下標變成價值,那麼從大到小遍歷所有可能的價值,第乙個體積小於總體積的價值就是答案;
用滾動陣列優化;
定義dp[i] : 表示 搶劫 i 價值的財物**的最小概率;
dp[0] = 0,dp[i] = inf;
轉移:dp[j] = min(dp[j],dp[j - w[i]] * (1.0 - v[i]) + (1.0 - dp[j - w[i]]) * v[i] +dp[j - w[i]] * v[i]);
但是這樣實在是太長了,考慮換一種狀態;
dp[i] : 表示 搶劫 i 價值的財物逍遙法外的最大概率;
dp[0] = 1,dp[i] = 0;
轉移 :dp[j] = max(dp[j],dp[j - w[i]] * (1.0 - v[i]));
注意不要漏掉狀態(加粗部分),找出狀態的所有情況是關鍵點
e:證明你學過動態規劃;
f:在另一篇博文裡講的很清楚了;
g:證明你學過動態規劃;
h:不難,但還是想了很長時間,首先要優化狀態,讓差的平方最小,則考慮到排序;
可以證明,排序後,當且僅當某數和前面乙個數或者它後面乙個數成對時,總的和最小;
因為 對於4個數,差是a,b,c。(a + b)^ 2 <= (a + c) ^ 2 + (b + c) ^ 2 和 (a + b + c) ^ 2 + b ^ 2;
dp[i][j] : 前i個數選2 * j個數字d的最小值;
dp[i][j] = min( dp[i - 1][j],dp[i - 2][j - 1] + (a[i] - a[i - 1]) * (a[i] - a[i - 1]) );
注意初始化dp[i][0] = 0; 因為dp[i][j] 會由此狀態轉移過去;
因為這個點,wa了很長時間。
所以當確定方程狀態正確時,應注意邊界和初始化是否正確;
i:樹形dp,和j題差不多;
j:樹形dp;
dp[ii][0/1] : 表示是否選i點;
dp[i][0] += max(dp[v][1],do[v][0]); v是i的子結點;
dp[i][1] += dp[v][0];
k:樹形dp + 揹包:
dp[x][i][j],表示以x為根的子樹中,前i個子結點,攻破j個城市獲得最大的寶物價值;
用滾動陣列可以優化掉一維;
a:
#include#include#include#includeusing namespace std;
const int maxn = 100001 + 11;
int v[maxn],dp[maxn],cnt[maxn];
int n,v,ans,tot,t;
void solve()
v[++ tot] = (cnt[i] - (t << 1) + 1) * v[i];
} for(int i = 1;i <= tot;i ++)
for(int j = v;j >= v[i];j --)
dp[j] |= dp[j - v[i]];
for(int i = 1;i <= v;i ++) if(dp[i]) ans ++;
cout << ans << "\n";
return;
}int main()
d:
第一種:
#include#include#include#includeusing namespace std;
const int maxn = 20001 + 22;
int n,t,sum;
int w[maxn];
double v,v[maxn],dp[maxn],inf = 214483.0;
void solve()
for(int i = 0;i <= sum;i ++) dp[i] = inf;
dp[0] = 0.0;
for(int i = 1;i <= n;i ++)
for(int j = sum;j >= w[i];j --)
if(dp[j - w[i]] <= 1.0)
for(int i = sum;i >= 0;i --) }}
int main()
第二種:
#include#include#include#includeusing namespace std;
const int maxn = 20001 + 22;
int n,t,sum;
int w[maxn];
double v,v[maxn],dp[maxn],inf = 214483.0;
void solve()
for(int i = 0;i <= sum;i ++) dp[i] = inf;
dp[0] = 0.0;
for(int i = 1;i <= n;i ++)
for(int j = sum;j >= w[i];j --)
if(dp[j - w[i]] <= 1.0)
for(int i = sum;i >= 0;i --) }}
int main()
h:
#include#include#include#includeusing namespace std;
const int maxn = 2001 + 22;
int a[maxn],ma[maxn],dp[maxn][maxn];
int n,k;
void solve()
int main()
i:
#include#include#include#include#includeusing namespace std;
vectorg[1603];
int dp[1603][2];
int n;
void dfs(int x,int f)
return;
}void solve()
} dfs(0,-1);
cout << min(dp[0][0],dp[0][1]) << endl;
return;
}int main()
j:
#include#include#include#include#includeusing namespace std;
const int maxn = 10001;
int fa[maxn],a[maxn],dp[maxn][2];
int n,root;
vectorg[maxn];
void dfs(int x)
return;
}void solve()
while(1)
int x = 1;
while(fa[x] != -1) x = fa[x];
root = x,dfs(root);
cout << max(dp[root][0],dp[root][1]) << endl; }}
int main()
k:
#include#include#include#include#includeusing namespace std;
const int maxn = 205;
int size[maxn],a[maxn],dp[maxn][maxn];
int n,m,ans;
vectorg[maxn];
void init()
void dfs(int x)
return;
}void solve()
dfs(0);
cout << dp[0][m + 1] << endl;
return;
}int main()
return 0;
}
二分內容整理(待補充
內容來演算法競賽高階指南,我把自認為的重點寫了下來,方便檢視 while l 1 if a mid x r mid else l mid 1 cout 1 if a mid x l mid else r mid 1 cout關鍵是倆個寫法的的mid的取值,如果對第二段 也是 l r 1,那麼當r l...
java作業整理
題意 1.宣告乙個獅子類 lion 繼承自食肉動物類 carnivore 並且實現 runnable 介面。要求 1 寫出runnable 介面,並定義乙個返回值為空的方法 run 2 寫出 carnivore類,定義為抽象,封裝一屬性 int legs 寫出含有引數 int legs 的構造方法 ...
Java作業整理
題意 編寫乙個名為square 正方形 的類,並按要求完成如下封裝 要求 1 乙個名為 side 的double 私有資料域表示三條邊 2 乙個能建立帶指定引數引數 s1的構造方法 3 實現 comparable cloneable 介面。5 編寫方法,求 square 正方形 類物件的周長,返回 ...