Some DP and DP miscellaneous questions
1.
[HNOI2001] Product Processing
A simple backpack, but I still wrote QAQ for a long time.
The time range is smaller than 5. Obviously, one-dimensional backpacks are considered. dp [I] indicates that currently A consumes the minimum B consumption of I.
Note:
If (B [I]) dp [j] = dp [j] + B [I];
Else dp [j] = 1e9 + 7;
You can use B to directly transfer data. Otherwise, you must set the last status to positive infinity. You can only use the last two transfers.
//Twenty#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;const int maxn=6000+299;const int N=5*6000+9;int n,a[maxn],b[maxn],c[maxn],dp[N],lz[N],ans=1e9+7; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]); memset(dp,127,sizeof(dp)); dp[0]=0; for(int i=1;i<=n;i++) for(int j=i*5;j>=0;j--){ if(b[i]) dp[j]=dp[j]+b[i]; else dp[j]=1e9+7;//!!!!!!!!!!!!!!!!!!!! if(a[i]&&j>=a[i]&&dp[j]>dp[j-a[i]]) dp[j]=dp[j-a[i]]; if(c[i]&&j>=c[i]&&dp[j]>dp[j-c[i]]+c[i]) dp[j]=dp[j-c[i]]+c[i]; if(i==n) ans=min(max(dp[j],j),ans); } cout<<ans; return 0;}
View Code
2.
[HAOI2007] ascending sequence
It seems that the range of data is n ^ 2, but I did not write the nlongn Algorithm for Finding the longest ascending subsequence. I just YY it myself, and it is ugly to write it, in a monotonous stack, the length ranges from short to long and ranges from large to small. Two points are used. The longest value is smaller than the longest value, and whether the length is its position can be updated.
In this way, we can find the longest ascending sequence starting with each element and run from 1 to n to ask if it can be so long, which guarantees the minimum Lexicographic Order.
//Twenty#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<stack>#include<vector>using namespace std;const int maxn=10000+299;int now,n,m,x,maxx,a[maxn],pre[maxn],dp[maxn],sta[maxn],sl=1,sr;int ef(int l,int r,int x){ int res=-1; while(l<=r){ int mid=(l+r)>>1; if(a[sta[mid]]>x) res=mid,l=mid+1; else r=mid-1; } return res;}void ef2(int l,int r,int len,int x){ while(l<=r){ int mid=(l+r)>>1; if(dp[sta[mid]]==len) { if(a[sta[mid]]<=a[x]) sta[mid]=x; break;} if(dp[sta[mid]]<len) l=mid+1; else if(dp[sta[mid]]>len) r=mid-1; }}void work() { for(int i=n;i>=1;i--) { dp[i]=1; if(sl<=sr) { now=ef(sl,sr,a[i]); if(now!=-1) dp[i]=dp[sta[now]]+1; } maxx=max(maxx,dp[i]); while(sr>=sl&&dp[sta[sr]]<=dp[i]&&a[sta[sr]]<=a[i]) { sr--; } if(sr<sl||dp[sta[sr]]<dp[i]) sta[++sr]=i; else ef2(sl,sr,dp[i],i); }}void query(int x){ if(x>maxx) puts("Impossible"); else { int pre=0; for(int i=1;i<=n;i++) { if(dp[i]>=x&&a[i]>pre) { pre=a[i]; if(x==1) printf("%d",a[i]); else printf("%d ",a[i]); x--; if(!x) break; } } printf("\n"); }}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); work(); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d",&x); query(x); } return 0;}
View Code
However, the correct nlogn's longest ascending sequence is not written in this way. Only one second is used, but it is not very clear in the next step. I am too lazy to learn it later.
I learned how to use the line segment tree from the LLJ daxie. I opened a weight line segment tree and saved the Dp value from the back to the top. I found the maximum Dp value next to it for each vertex to update, it seems that the idea of nlogn is similar to that of normal nlogn.
3.
Ultraviolet A-12063 Zeros and Ones
Google Translate: Shen Keng. 1 and 0 are translated at the same frequency as 0 and 0. Why?
The Case is broken into a wave of cases .. QAQ discovered only when the camera is connected
The best way to do this is to add 0 or 1 in the future without special judgment, and not to blow up the whole process. If you add 0 or 1 in the future, you need to issue a special judgment, and then pay attention to the long, I want to simulate it twice to ensure it won't be fried (LLJ said I want to enable usinged long, because long is only 2 ^ 64-1, actually this question is only 2 ^ 63 so no)
//Twenty#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;typedef unsigned long long LL;const int maxn=100;const int maxk=105;int T,n,k;LL dp[maxn][maxn][maxk],ans,ll=1; void work(){ if(!k||n&1) {printf("0\n"); return;} memset(dp,0,sizeof(dp)); dp[0][0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=i;j++) for(int l=0;l<k;l++) { if(j) dp[i][j][(l+((ll=1)<<(i-1))%k)%k]+=dp[i-1][j-1][l]; if(i!=n) dp[i][j][l]+=dp[i-1][j][l]; } ans=0; printf("%llu\n",dp[n][n/2][0]);}int main(){ scanf("%d",&T); for(int i=1;i<=T;i++){ scanf("%d%d",&n,&k); printf("Case %d: ",i); work(); } return 0;}
View Code
This is a later version.
for(int i=1;i<n;i++) for(int j=0;j<=i;j++) for(int l=0;l<k;l++) { dp[i+1][j+1][((l<<1)|1)%k]+=dp[i][j][l]; dp[i+1][j][(l<<1)%k]+=dp[i][j][l]; }
4.
Ultraviolet A-1628 Pizza Delivery
I love the memory-based search, and the memory-based search is the strongest.
Dp [I] [j] [o] [k] indicates that the order from I to j has been processed. Now I or j still need to deliver the optimal solution to k
Enumeration and memory
for(int i=1;i<l;i++) u=max(u,dfs(i,r,0,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r])); for(int i=n;i>r;i--) u=max(u,dfs(l,i,1,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r]));
Note that this section can be searched first and then in the middle to achieve the effect of memory.
Code
//Twenty#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;const int maxn=100+5;int T,now,dp[maxn][maxn][2][maxn],vis[maxn][maxn][2][maxn],n,p[maxn],e[maxn],ans;int dfs(int l,int r,int o,int k) { if(k==0) return 0; if(vis[l][r][o][k]==now) return dp[l][r][o][k]; vis[l][r][o][k]=now; int &u=dp[l][r][o][k]; u=0; for(int i=1;i<l;i++) u=max(u,dfs(i,r,0,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r])); for(int i=n;i>r;i--) u=max(u,dfs(l,i,1,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r])); return u; }int main(){ scanf("%d",&T); for(now=1;now<=T;now++) { ans=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&p[i]); for(int i=1;i<=n;i++) scanf("%d",&e[i]); for(int kk=1;kk<=n;kk++) for(int i=1;i<=n;i++) ans=max(ans,dfs(i,i,0,kk-1)+e[i]-kk*abs(p[i])); printf("%d\n",ans); } return 0;}
View Code