簡單暴力到dp的優化(中級篇)

下面再放三道我比較喜歡的,需要好好寫一下的題。

第一題比較水

1. White Cloud is exercising in the playground. White Cloud can walk 1 meters or run k meters per second. Since White Cloud is tired,it can't run for two or more continuous seconds. White Cloud will move L to R meters. It wants to know how many different ways there are to achieve its goal. Two ways are different if and only if they move different meters or spend different seconds or in one second, one of them walks and the other runs.

輸入描述: The first line of input contains 2 integers Q and k.Q is the number of queries.(Q<=100000,1<=k<=100000) For the next Q lines,each line contains two integers L and R.(1<=L<=R<=100000)

輸出描述: For each query,print a line which contains an integer,denoting the answer of the query modulo 1000000007.

示例1: 輸入 3 3 3 3 1 4 1 5 輸出 2 7 11

題目大意

白云在健身,每秒可以走1米或跑k米,并且不能連續兩秒都在跑。 當它的移動距離在[L,R]之間時,可以選擇結束鍛煉。 問有多少種方案結束。

做法

DP? f[i][0/1]表示已經過了i米,最后一步是跑還是走的方案數,分開就很好寫了,簡單,自己體會。 f[i][1]=f[i-k][0],f[i][0]=f[i-1][0]+f[i-1][1] 注意要記錄前綴和。

?

#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll g[100005];
ll dp[100005][2];
int main(void)
{int q,k,a,b;ll sum;cin>>q>>k;dp[0][0]=1;for(int i=1;i<=100000;++i){dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD;if(i-k>=0)dp[i][1]=(dp[i-k][0])%MOD;}sum=0;for(int i=1;i<=100000;++i){g[i]=(dp[i][0]+dp[i][1]+sum);sum=g[i];}// for(int i=9000;i<=100000;++i){//     cout<<g[i]<<endl;// }while(q--){cin>>a>>b;cout<<(g[b]-g[a-1])%MOD<<endl;}return 0;
}

?

2、來一發多重背包

選這個題是感覺代碼有一種美感。。。。。

一. 編程題

1. Since then on, Eddy found that physics is actually the most important thing in the contest. Thus, he wants to form a team to guide the following contestants to conquer the PACM contests(PACM is short for Physics, Algorithm, Coding, Math).

There are N candidate groups each composed of pi physics experts, ai algorithm experts, ci coding experts, mi math experts. For each group, Eddy can either invite all of them or none of them. If i-th team is invited, they will bring gi knowledge points which is calculated by Eddy's magic formula. Eddy believes that the higher the total knowledge points is, the better a team could place in a contest. But, Eddy doesn't want too many experts in the same area in the invited groups. Thus, the number of invited physics experts should not exceed P, and A for algorithm experts, C for coding experts, M for math experts.

Eddy is still busy in studying Physics. You come to help him to figure out which groups should be invited such that they doesn't exceed the constraint and will bring the most knowledge points in total.

輸入描述: The first line contains a positive integer N indicating the number of candidate groups. Each of following N lines contains five space-separated integer p i, ai, ci, mi, gi indicating that i-th team consists of pi physics experts, ai algorithm experts, ci coding experts, mi math experts, and will bring gi knowledge points. The last line contains four space-separated integer P, A, C, M indicating the maximum possible number of physics experts, algorithm experts, coding experts, and math experts, respectively.

?1 ≤ N ≤ 36 0 ≤ pi,ai,ci,mi,gi ≤ 36 0 ≤ P, A, C, M ≤ 36

輸出描述: The first line should contain a non-negative integer K indicating the number of invited groups. The second line should contain K space-separated integer indicating the index of invited groups(groups are indexed from 0).

You can output index in any order as long as each index appears at most once. If there are multiple way to reach the most total knowledge points, you can output any one of them. If none of the groups will be invited, you could either output one line or output a blank line in the second line.

題干有點長,其實就是每個隊有四種代價,一個價值。多重背包。36的五次方竟然沒超時也是醉了。。

?

#include <bits/stdc++.h>
using namespace std;
const int N=37;
int n, p[N], a[N], c[N], m[N], g[N];
int P, A, C, M;
short dp[N][N][N][N][N];
bool tk[N][N][N][N][N];
int main(){cin>>n;for(int i=0; i<n; i++)cin>>p[i]>>a[i]>>c[i]>>m[i]>>g[i];cin>>P>>A>>C>>M;for(int i=0; i<=n; i++)for(int ip=0; ip<=P; ip++)for(int ia=0; ia<=A; ia++)for(int ic=0; ic<=C; ic++)for(int im=0; im<=M; im++)tk[i][ip][ia][ic][im]=false;for(int i=0; i<n; i++){for(int ip=P; ip>=0; ip--)for(int ia=A; ia>=0; ia--)for(int ic=C; ic>=0; ic--)for(int im=M; im>=0; im--)dp[i+1][ip][ia][ic][im]=dp[i][ip][ia][ic][im];for(int ip=P; ip>=p[i]; ip--)for(int ia=A; ia>=a[i]; ia--)for(int ic=C; ic>=c[i]; ic--)for(int im=M; im>=m[i]; im--)if(dp[i][ip-p[i]][ia-a[i]][ic-c[i]][im-m[i]]+g[i]>dp[i+1][ip][ia][ic][im]){dp[i+1][ip][ia][ic][im]=dp[i][ip-p[i]][ia-a[i]][ic-c[i]][im-m[i]]+g[i];tk[i+1][ip][ia][ic][im]=true;}}fprintf(stderr, "ans=%d\n", dp[n][P][A][C][M]);vector<int> ans;for(int i=n; i>=1; i--)if(tk[i][P][A][C][M]){ans.push_back(i-1);P-=p[i-1];A-=a[i-1];C-=c[i-1];M-=m[i-1];}reverse(ans.begin(), ans.end());printf("%d\n", (int)ans.size());for(size_t i=0; i<ans.size(); i++)printf("%d%c", ans[i], " \n"[i+1==ans.size()]);
}

3、P1040 加分二叉樹

題目

https://www.luogu.org/problemnew/show/P1040

設一個?nn?個節點的二叉樹tree的中序遍歷為(?1,2,3,…,n1,2,3,…,n?),其中數字?1,2,3,…,n1,2,3,…,n?為節點編號。每個節點都有一個分數(均為正整數),記第?ii?個節點的分數為?di,treedi,tree?及它的每個子樹都有一個加分,任一棵子樹?subtreesubtree?(也包含?treetree?本身)的加分計算方法如下:

subtreesubtree?的左子樹的加分×?subtreesubtree?的右子樹的加分+?subtreesubtree?的根的分數。

若某個子樹為空,規定其加分為?11?,葉子的加分就是葉節點本身的分數。不考慮它的空子樹。

試求一棵符合中序遍歷為(?1,2,3,…,n1,2,3,…,n?)且加分最高的二叉樹?treetree?。要求輸出;

(1)?treetree?的最高加分

(2)?treetree?的前序遍歷

思路:這個題可以用動態規劃或者記憶化搜索來做。因為如果要求加分最大的話,必須要求它的兒子結點加分最大,所以就有了最優子階段。我們可以枚舉根來更新最大值。

root[i,j]表示[i,j]這段序列的根,遞歸輸出先序遍歷。注意初始化,f[i][i]=v[i],當序列只有I一個元素時,f[i][i]等于這個點本身的權值,當l==r-1時,此時是空樹設為1。

?

#include<iostream>
#include<cstdio>
using namespace std;
int n,v[39],f[47][47],i,j,k,root[49][49];
void print(int l,int r){if(l>r)return;if(l==r){printf("%d ",l);return;}printf("%d ",root[l][r]);print(l,root[l][r]-1);print(root[l][r]+1,r);
}
int main() {scanf("%d",&n);for( i=1; i<=n; i++) scanf("%d",&v[i]);for(i=1; i<=n; i++) {f[i][i]=v[i];f[i][i-1]=1;}for(i=n; i>=1; i--)for(j=i+1; j<=n; j++)for(k=i; k<=j; k++) {if(f[i][j]<(f[i][k-1]*f[k+1][j]+f[k][k])) {f[i][j]=f[i][k-1]*f[k+1][j]+f[k][k];root[i][j]=k;}}printf("%d\n",f[1][n]);print(1,n);return 0;
}

?

?

?

?

?

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445662.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第二次課 課上代碼

敲一遍&#xff0c;體會每行代碼想表達的意思。 第二講 創建.py文件 數據類型&#xff1a;布爾(and\or\not) 條件判斷語句(if elif else) 列表基礎操作&#xff08;特點、創建、增加元素、len()、下標、py切片&#xff09; >>> 5>4 True >>> 4>5 Fa…

第一次課 優秀作業展示

18級河北師大軟件編程訓練 很多同學非常認真的完成了作業&#xff0c;這里選出比較優秀的作業展示出來。 注&#xff1a;展示順序不是排名 為了尊重同學們的勞動成果&#xff0c;并沒有要代碼&#xff0c;只是截圖展示。 范天祚 &#xff08;傻兔子&#xff09; 熊靜祎&…

dp打開思路:HDU1029 HDU1087 HDU1176?HDU1257 POJ1458(水題不水)

題目&#xff1a;https://vjudge.net/contest/68966#overview HDU - 1029 題意&#xff1a;找出出現次數超過一半的數字 蠢思路&#xff1a;排序找中間 DP&#xff1a;掃一遍一個變量count記錄解出現的次數&#xff0c;是當前解就&#xff0c;否則--&#xff0c;count為負就…

dp打開思路2:POJ2533 HDU1114 HDU1260 HDU1160(水題不水)

題目&#xff1a;https://vjudge.net/contest/68966#overview POJ2533 最長上升子序列&#xff0c;很平常的題&#xff0c;但是維持單調隊列二分還是值得一貼的&#xff0c;O(nlogn) 關鍵思想&#xff1a;出現在單調隊列里的數都在當前接收的數之前&#xff0c;所以找到最小…

二分查找及一般拓展總結

二分-不止是查找哦 二分過程&#xff1a;首先&#xff0c;假設表中元素是按升序排列&#xff0c;將表中間位置記錄的關鍵字與查找關鍵字比較&#xff0c;如果兩者相等&#xff0c;則查找成功&#xff1b;否則利用中間位置記錄將表分成前、后兩個子表&#xff0c;如果中間位置記…

第三次課 課上代碼

這次可能比較簡短&#xff0c;這樣也好&#xff0c;可讀性比較強。 別問我為什么&#xff0c;我不會告訴你們我把代碼關了的哼哼。 簡單復習、注意事項及小知識強調講解 作業講解 列表的遍歷 For循環&#xff08;這個參考切片&#xff0c;視頻有詳細講解&#xff0c;一樣的…

排序算法基本介紹及python實現(含詳細注釋)

對數組排序可以說是編程基礎中的基礎&#xff0c;本文對八種排序方法做簡要介紹并用python實現。 代碼中注釋很全&#xff0c;適合復習和萌新學習。這是剛入學自己寫的&#xff0c;可能難免比不上標準的寫法&#xff0c;但是懶得改了。 文末會放和排序相關的基本拓展總結鏈接…

第二次作業 講解及展示

第二次作業&#xff0c;同學們雖然在認真完成&#xff0c;但是或多或少都出了一些錯誤&#xff0c;一班張婷&#xff0c;四班武儀人&#xff0c;六班楊澤宇&#xff0c;八班候雯潔&#xff0c;安錦陽&#xff0c;劉凈圓&#xff0c;這些同學完成的較為出色&#xff0c;錯誤較少…

深搜DFS\廣搜BFS 圖初步入門

首先&#xff0c;不管是BFS還是DFS&#xff0c;由于時間和空間的局限性&#xff0c;它們只能解決數據量比較小的問題。 深搜&#xff0c;顧名思義&#xff0c;它從某個狀態開始&#xff0c;不斷的轉移狀態&#xff0c;直到無法轉移&#xff0c;然后退回到上一步的狀態&#xf…

素數基本(埃氏篩法/線性篩法)

一、檢查n是否為素數 最簡單思路&#xff1a;所有可能的因數全部試一遍。 int gg(int n) {for(int i2;i<n;i){if((n%i)0)return 0;//有因數就不是素數咯}return 1; } 進一步思考&#xff1a;沒必要枚舉所有的數&#xff0c;每一個小于n^(1/2)的因數i&#xff0c;一定有一個大…

歐幾里得gcd/extend_gcd

正式敘述前還寫了一點自己的小感受。 問題&#xff1a;求兩個正整數a&#xff0c;b的最大公約數。 大神看來是很簡單的問題&#xff0c;但是對于去年夏天剛學python的我來說&#xff0c;這是個很難的問題&#xff0c;還記得當時一晚上睡不著都在想怎么快一點的求出最大公約數…

python基礎技巧總結(一)

最近總結一下python基礎知識&#xff0c;就暫時棄坑了。 本文總結只屬于python的一些騷操作。。。 后面文章自行去博客學習交流 原地交換 Python 提供了一個直觀的在一行代碼中賦值與交換&#xff08;變量值&#xff09;的方法 x, y 10, 20 print(x, y)x, y y, x print(x…

python基礎技巧總結(二)

一總結的鏈接&#xff1a; 好&#xff0c;我們繼續 一次性初始化多個變量 可以直接賦值&#xff1a; a,b,c,d1,2,3,4 可以利用列表&#xff1a; List [1,2,3] x,y,zList print(x, y, z) #-> 1 2 3 &#xff08;元素個數應與列表長度相同&#xff09; 打印模塊路徑 im…

python基礎技巧總結(三)

前兩篇文章&#xff1a; https://blog.csdn.net/hebtu666/article/details/81698235 https://blog.csdn.net/hebtu666/article/details/81698329 我們繼續總結&#xff1a; 開啟文件分享 Python 允許運行一個 HTTP 服務器來從根路徑共享文件&#xff0c;下面是開啟服務器的…

python基礎技巧總結(四)

前三期請到我博客里找 https://blog.csdn.net/hebtu666 我們繼續總結 except的用法和作用 try/except: 捕捉由PYTHON自身或寫程序過程中引發的異常并恢復 except: 捕捉所有其他異常 except name: 只捕捉特定的異常 except name, value: 捕捉異常及格外的數據(實例) exce…

python基礎技巧總結(五)

前四期到博客找&#xff1a;https://blog.csdn.net/hebtu666 我們繼續說一些好用的函數 split Python split() 通過指定分隔符對字符串進行切片&#xff0c;如果參數 num 有指定值&#xff0c;則僅分隔 num 個子字符串。 語法&#xff1a; str.split(str"", num…

堆的簡單實現

關于堆不做過多介紹 堆就是兒子的值一定不小于父親的值并且樹的節點都是按照從上到下&#xff0c;從左到右緊湊排列的樹。 &#xff08;本文為二叉堆&#xff09; 具體實現并不需要指針二叉樹&#xff0c;用數組儲存并且利用公式找到父子即可。 父&#xff1a;(i-1)/2 子:…

二叉搜索樹實現

本文給出二叉搜索樹介紹和實現 首先說它的性質&#xff1a;所有的節點都滿足&#xff0c;左子樹上所有的節點都比自己小&#xff0c;右邊的都比自己大。 那這個結構有什么有用呢&#xff1f; 首先可以快速二分查找。還可以中序遍歷得到升序序列&#xff0c;等等。。。 基本操…

python基礎小白題

題目1&#xff1a;有1、2、3、4四個數&#xff0c;能組成多少個互不相同且無重復的三位數&#xff1f;都是多少&#xff1f; list_num[1,2,3,4] all_num[] for i in list_num: for j in list_num: for k in list_num : if (i!j) and (i!k) and (j!k): numi*100j*10k all_num…

python基礎小白題2

題目11&#xff1a;判斷101-200之間有多少個素數&#xff0c;并輸出所有素數。 num[] for i in range(100,201): ji//2 for k in range(2,j): if i%k0: break else: num.append(i) print(一共有%d個素數\n這些素數是&#xff1a; %len(num),num ) 輸出結果&am…