动态规划初步
题目列表 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
B3635 硬币问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
using ll=long long;
const int N=1e6+10;
const int mod=1e9+7;
int n,s,a,b;
int f[N];
void solve()
{
std::cin>>n;
for(int i=1;i<=n;i++)
{
f[1]=1,f[5]=1,f[11]=1;
f[i]=f[i-1]+1;
if(i>5)
{
f[i]=std::min(f[i],f[i-5]+1);
}
if(i>11)
{
f[i]=std::min(f[i],f[i-11]+1);
}
}
std::cout<<f[n];
}
signed main()
{
int t=1;
//std::cin>>t;
while(t--)
{
solve();
}
return 0;
}
B3636 文字工作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题硬币很像,就是判断条件不同。只有偶数才能转移。
#include<bits/stdc++.h>
using ll=long long;
const int N=1e6+10;
const int mod=1e9+7;
int n,s,a,b;
int f[N];
void solve()
{
std::cin>>n;
f[1]=0;
for(int i=2;i<=n;i++)
{
f[i]=f[i-1]+1;
if(i%2==0)
{
f[i]=std::min(f[i],f[i/2]+1);
}
}
std::cout<<f[n];
}
signed main()
{
int t=1;
//std::cin>>t;
while(t--)
{
solve();
}
return 0;
}
B3637 最长上升子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
输入一个长为n的序列,输出这个序列最长上升子序列的长度。
DP n方
定义f【N】代表终点为位置i的最长上升子序列的长度。
因此外层直接枚举,内层循环枚举前面的点能否作为上一个点,并存答案取最大值即可。
#include<bits/stdc++.h>
using ll=long long;
const int N=1e6+10;
const int mod=1e9+7;
int n;
int a[N],f[N];//以i结尾必须选i
void solve()
{
std::cin>>n;
for(int i=1;i<=n;i++)
{
std::cin>>a[i];
f[i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)//遍历前面的
{
if(a[i]>a[j])
{
f[i]=std::max(f[i],f[j]+1);
}
}
}
int maxn=-1;
for(int i=1;i<=n;i++)
{
maxn=std::max(maxn,f[i]);
}
std::cout<<maxn;
}
signed main()
{
int t=1;
//std::cin>>t;
while(t--)
{
solve();
}
return 0;
}
单调队列 nlogn
依次枚举每个数,这个数比前面大就直接入队。
如果后面的数比前面还小,就找到队中第一个比这个>=数,替换。
这样做不保证队列中元素就是答案,但是长度一定是对的。
#include<bits/stdc++.h>
using ll=long long;
const int N=100000+10;
int a[N];
int len=0;
int q[N],cnt;
signed main()
{
int n;
std::cin>>n;
for(int i=1;i<=n;i++)
{
std::cin>>a[i];
}
for(int i=1;i<=n;i++)//大的就入栈,否则替换>的第一个数
{//只有换栈顶的时候会影响后面的结果,能换栈顶则说明前面存在cnt-1个数比它小
if(cnt==0||a[i]>q[cnt]) q[++cnt]=a[i];
else{
int l=1,r=cnt,res=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(q[mid]>=a[i])
{
res=mid;
r=mid-1;
}else l=mid+1;
}
q[res]=a[i];
}
}
std::cout<<cnt;
return 0;
}
P6759 [USACO2006 OPEN] 县集市 The County Fair - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
输入n个摊位收到礼物的时间。输入每两个摊位之间的距离,求能获得的最多的礼物数量。
首先将摊位按照收到礼物的时间从小到大排序,同时记得存上时间为0时在摊位1处。
然后从小到大枚举摊位,枚举前面时间的摊位,如果距离赶得上g[a[j].num][a[i].num]+a[j].t<=a[i].t就可以更新答案。
这题与最长上升子序列的长度唯一的区别就是要先对摊位按时间排序,然后判断。
#include<bits/stdc++.h>
using ll=long long;
const int N=410;
const int mod=1e9+7;
int n;
int g[N][N];
int f[N];
int maxn=-1;
struct node{
int num,t;
}a[N];
bool cmp(node a,node b){
return a.t<b.t;
}
void solve()
{
std::cin>>n;
for(int i=1;i<=n;i++)
{
std::cin>>a[i].t;
a[i].num=i;
}
std::sort(a+1,1+a+n,cmp);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
std::cin>>g[i][j];
}
}
a[0]={1,0};
int maxn=0;
for(int i=1;i<=n;i++)//按时间看
{
for(int j=0;j<i;j++)
{
if(g[a[j].num][a[i].num]+a[j].t<=a[i].t)
f[i]=std::max(f[i],f[j]+1);
}
maxn=std::max(f[i],maxn);
}
std::cout<<maxn;
}
signed main()
{
int t=1;
//std::cin>>t;
while(t--)
{
solve();
}
return 0;
}