DP
DP是什么
就我而言,DP是需要做出最优选择的一种题目,而且是全局最优的选择
DP有个性质,是相关性,就后面做的决策可以在之前做的决策上进行
而且没有后效性
数组的下标代表状态,数组中数的值代表value
贴一个题
D - Snuke Panic (1D) (atcoder.jp)
这个题的状态转移方程是dp[x][t]=max(dp[x-1][t-1],dp[x][t-1],dp[x+1][t-1])+a[x]
key : fup(j,0,min(4ll,i)
这道题一个很关键的地方就是上面的key,如果j>i的话,那就是不可能走到的,由此获得的状态也是不可能的,会干扰后续的计算
const int N=2e5+10;
int n,m,k,x,y,z;
int f[N][10],s[N][10];
void solve(){
//try it again.
cin>>n;
int maxt=0;
up(1,n){
cin>>x>>y>>z;
s[x][y]=z;
maxt=max(maxt,x);
}
f[0][0]=0;
fup(i,1,maxt){
fup(j,0,min(4ll,i)){
if(j){
f[i][j]=max(f[i-1][j],f[i-1][j-1]);
}
f[i][j]=max({f[i-1][j],f[i-1][j-1],f[i-1][j+1]});
f[i][j]+=s[i][j];
}
}
int ans=0;
for(int i=0;i<=4ll;i++)
ans=max(ans,f[maxt][i]);
// debug(ans);
cout<<ans;
}
今天补了一道Div2的C题,也是一道DP
这个题是用dfs来完成状态的转移的
int n,m,k,a[N],b[N],p[N];
int f[N][N];
void solve(){
//try it again.
cin>>n;
up(1,n)cin>>a[o];
sort(a+1,a+1+n);
mem1(f);
function<int(int,int)>dfs=[&](int l,int r){
if(l==r)return f[l][r]=0;
if(f[l][r]!=-1)return f[l][r];
f[l][r]=min(dfs(l,r-1),dfs(l+1,r))+(a[r]-a[l]);
return f[l][r];
};
dfs(1,n);
puts(f[1][n]);
}
今天Acwing的周赛最后一题也是一个DP
可惜我当搜索写的,然后TLE了呜呜呜
4796. 删除序列
给定一个长度为 n
的正整数序列 a。
你可以进行任意次删除操作。
每次删除操作分为两步:
- 选择序列中的一个元素(不妨设其元素值为
x
),并将这一个元素删除,这可以给你加x
分。 - 将所有的元素值为
x-1
和x+1
的元素(如果有的话)从序列中删除,这不会给你带来任何分数。
请计算,通过删除操作,你可以获得的最大得分。
输入格式
第一行包含整数 n
。
第二行包含 n
个正整数 a[1],a[2],a[3].....a[n]
。
输出格式
一个整数,表示可以获得的最大得分。
数据范围
前 6个测试点满足 1<=n<=10
。
所有测试点满足 1 <=n <= 10^5
,1 <= a[i] <= 10^5
。
输入样例1:
2
1 2
输出样例1:
2
输入样例2:
3
1 2 3
输出样例2:
4
输入样例3:
9
1 2 1 3 2 2 2 2 3
输出样例3:
10
我们可以发现每一个点能不能选只与前一个点的状态有关
if(前面的点选了) then 这个点不能选
if(前面的点没有选) then 这个点可以选也可以不选
由此我们可以推出方程f[i][0]=max(f[i-1][1],f[i-1][0])
f[i][1]=max(f[i][0],f[i-1][0]+cnt[i]*i)
正确代码:
int n,m,k,a[N],b[N],p[N];
int f[N][2];
void solve(){
//try it again.
cin>>n;
up(1,n){
int x;
cin>>x;
a[x]++;
}
fup(i,1,100000){
f[i][0]=max(f[i-1][0],f[i-1][1]);
f[i][1]=f[i-1][0]+a[i]*i;
}
puts(max(f[100000][0],f[100000][1]));
}
因为本人是小白所以想的搜索TLE15了哈哈哈
我滴TLE代码:
const int N=100005;
int n,m,k,a[100005],b[N],p[N];
bool stt[100050];
int mp[100050];
map<PII,bool>st;
void solve(){
//try it again.
cin>>n;
up(1,n)cin>>a[o];
mem0(mp);
st.clear();
mem0(stt);
sort(a+1,a+1+n);
up(1,n){
stt[a[o]]=true;
mp[a[o]]++;
}
int ans=0;
int maxl=a[n];
function<void(bool,int,int)>dfs=[&](bool state,int x,int carry){
if(st[{state,x}]>carry)return;
st[{state,x}]=carry;
if(x==maxl+1){
ans=max(ans,carry);
return;
}
if(!stt[x]){dfs(false,x+1,carry);return;}
if(state==true)dfs(false,x+1,carry);
else dfs(true,x+1,carry+mp[x]*x),dfs(false,x+1,carry);
};
dfs(false,0,0);
puts(ans);
}
其实本来一开始想写DP的QWQ,可惜脑子混了写了个DP[2][2][2][N]
这样的鬼东西,于是乎死活没写出来
后来理清楚思路又转到搜索了,然后好不容易搜索的思路对了,于是就TLE了哈哈哈
就这样与第一次AK擦肩而过
不过学到了DP
依然是很开心啦!
1/15补了一道 预处理的DP题
补了一道预处理的DP
For the first test,
For the second test,
For the third test,
For the fourth test,
题目给出
和 ,要求出 经过 次操作以后的长度
要
我们可以分析知道 给出的n
当中每一个位置上都可以视为单独进行的操作
n与n-1之间也存在着联系
由此便可以形成状态之间的关系
下面给出 key code
const int N=2e5+10;
const int mod=1e9+7;
int n,m,k,a[N],b[N],p[N];
struct point{
int cnt[10];
int len;
}dp[N];
void solve(){
//try it again.
cin>>n>>m;
int ans=0;
while(n){
(ans+=dp[n%10+m].len)%=mod;
n/=10;
}
puts(ans);
}
signed main(){
IOS;
dp[0].len=1;
dp[0].cnt[0]=1;
fup(o,1,N){
(dp[o].len=dp[o-1].len+dp[o-1].cnt[9])%=mod;
fup(j,1,9){
(dp[o].cnt[j]+=dp[o-1].cnt[j-1])%=mod;
}
(dp[o].cnt[1]+=dp[o-1].cnt[9])%=mod;
(dp[o].cnt[0]+=dp[o-1].cnt[9])%=mod;
}
int __;
cin>>__;
while(__--)
solve();
return 0;
}
这个题取模的方法很妙,偷了
本文作者:liangqianxing
本文链接:https://www.cnblogs.com/liangqianxing/p/17048173.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步