dp题
1.luogu 1484种树
50分思路:dp,但是数据规模过大没法dp选择奇怪贪心
dp方程 到i坑种j树 dp[i][j]=max(dp[i-1][j],dp[i-2][j-1])
100分思路:奇怪贪心,全部树坑中最大的i ,每次选择实际上需要选的是max(a[i],a[l]+a[r]);
但是如此转移十分困难,可以进行如下操作:
1.ans+=a[i]
2.设立新节点,利用链表存储各节点间位置关系,新节点的值为a[l]+a[r]-a[i],若日后选入新节点,意味着实际上选择了i两侧的点,未选则最终选择就是i
3.利用优先队列维护上述值,需要取出堆顶值为负则停止进行,并且需要取小于限制的数量
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=500010; struct node{ ll v;int id; bool operator <(node a)const{ return v<a.v;}}; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} ll a[N],ans; int l[N],r[N],vis[N]; priority_queue<node> q; int n,k; int main(){ n=read();k=read(); for(int i=1;i<=n;i++){ a[i]=read(); q.push((node){a[i],i}); l[i]=i-1;r[i]=i+1; }int len=n; for(int i=1;i<=k;i++){ while(!q.empty()&&vis[q.top().id]) q.pop(); if(q.empty()||q.top().v<0) break; node u=q.top();q.pop(); ans+=u.v; vis[u.id]=vis[l[u.id]]=vis[r[u.id]]=1; a[++len]=a[l[u.id]]+a[r[u.id]]-a[u.id]; l[len]=l[l[u.id]],r[len]=r[r[u.id]]; r[l[len]]=len;l[r[len]]=len; q.push((node){a[len],len}); }printf("%lld\n",ans); return 0; }
2.最大子段和
转移方程:f[i]=max(a[i],f[i-1]+a[i]) 最大子段和
e.g:给为n序列a,f(l,r)=i由l到r,求g[i]*(-1)的(r-i)次方 ,1<=l<=r<=n,求f(l,r)max
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; ll b[100005],c[100005],g[100050],ans; int main(){int n;scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld",&g[i]); if(i&1) g[i]=-g[i];} for(int i=1;i<=n;i++){ b[i]=max(g[i],b[i-1]+g[i]); c[i]=min(g[i],c[i-1]+g[i]);} for(int i=1;i<=n;i++){ if(i&1) ans=max(ans,-c[i]); else ans=max(ans,b[i]);} printf("%lld\n",ans);return 0; }
3.dp数方案数的模板题
放置某个东西,限制:相隔k个求总方案数 利用前缀和前缀dp
#include<bits/stdc++.h> #define LL long long #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; const int N=100500; const int mod=5000011; LL n,k,dp[N],s[N]; int main(){ scanf("%lld%lld",&n,&k); rep(i,1,n) dp[i]=1; rep(i,1,n){ if(i>k) dp[i]=(dp[i]+s[i-1-k])%mod; s[i]=(s[i-1]+dp[i])%mod;} printf("%d",s[n]+1);return 0;}