【線性DP】【lgP1336】最佳課題選擇
傳送門
Description
Matrix67要在下個月交給老師n篇論文,論文的內容可以從m個課題中選擇。由於課題數有限,Matrix67不得不重復選擇一些課題。完成不同課題的論文所花的時間不同。具體地說,對於某個課題i,若Matrix67計劃一共寫x篇論文,則完成該課題的論文總共需要花費Ai*x^Bi個單位時間(系數Ai和指數Bi均為正整數)。給定與每一個課題相對應的Ai和Bi的值,請幫助Matrix67計算出如何選擇論文的課題使得他可以花費最少的時間完成這n篇論文。
Input
第一行有兩個用空格隔開的正整數n和m,分別代表需要完成的論文數和可供選擇的課題數。
以下m行每行有兩個用空格隔開的正整數。其中,第i行的兩個數分別代表與第i個課題相對應的時間系數Ai和指數Bi。
Output
輸出完成n篇論文所需要耗費的最少時間。
Sample Input
10 3 2 1 1 2 2 1
Sample Output
19
Hint
對於30%的數據,n<=10,m<=5; 對於100%的數據,n<=200,m<=20,Ai<=100,Bi<=5。
Solution
第一次定義的方程為f[i]表示寫前i篇論文的最小花費,發現無法轉移。因為a*(x+y)^b顯然不等於a*x^b+a*y^b。考慮階段劃分:對於同一種課題的花費,在一個狀態中要一次性計算下來,否則就會出現無法轉移的情況。由此可將課題種類數作為階段,設f[i][j]表示用前i個課題寫j篇論文的花費。轉移顯然:f[i][j]=min{f[i-1][k]+a[i]*pow((j-k),b[i])|其中k<j
對於邊界,f[i][0]=0,其中i∈[0,m]
Code
#include<cstdio> #include<cstring> #define maxn 205 #define maxm 25 #define ll long long int inline void qr(ll &x) { char ch=getchar();ll f=1; while(ch>‘9‘||ch<‘0‘) { if(ch==‘-‘) f=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x*=f; return; } inline ll max(ll a,ll b) {return a>b?a:b;} inline ll min(ll a,ll b) {return a<b?a:b;} inline void swap(ll &a,ll &b) { ll c=a;a=b;b=c;return; } ll n,m,frog[maxn][maxn]; struct Pa { ll a,b; }; Pa pa[maxn]; ll pow(ll a,ll b) { if(!b) return 1; if(!(b^1)) return a; ll t=b/2; ll an=pow(a,t); if(b%2) return an*an*a; else return an*an; } int main() { qr(n);qr(m); for(int i=1;i<=m;++i) { qr(pa[i].a);qr(pa[i].b); } std::memset(frog,0x3f,sizeof frog);frog[0][0]=0; for(int i=1;i<=m;++i) frog[i][0]=0; for(int i=1;i<=m;++i) { for(int j=1;j<=n;++j) { for(int k=0;k<=j;++k) { frog[i][j]=min(frog[i][j],frog[i-1][j-k]+pa[i].a*pow(k,pa[i].b)); } } } printf("%lld\n",frog[m][n]); return 0; }
Summary
1、不要閑的沒事一上來就壓維。發現狀態不對容易懵逼
2、在設計狀態的時候,一般而言需要在一個狀態中需要一次性計算的會被作為階段進行劃分,劃分時註意感性領悟一下無後效性原則,不要悶頭方程。
3、在不壓維狀態下若以一個維度為階段無法轉移可以嘗試使用另一個維度作為階段
4、對於看起來需要記錄以往信息但又明顯不是狀壓的DP(例如本題若使用論文數作為階段需要記錄對於每一個狀態每一個課題選了多少),一般而言會把需要記錄的信息作為階段,目的還是,方便一次性計算。
End on 2018/6/3
【線性DP】【lgP1336】最佳課題選擇