专栏文章
题解:CF413D 2048
CF413D题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mipkk88s
- 此快照首次捕获于
- 2025/12/03 13:31 3 个月前
- 此快照最后确认于
- 2025/12/03 13:31 3 个月前
题意简述:
给定长度为 的序列,将其进行 次操作,每次压入一个 或者 ,之后以题目中给定的游戏规则,即 游戏规则进行合并,最后要求给出可行的方案数量,使得序列中的最大数大于 。
思路分析:
看到这道题的 居然如此之小,再者要求方案数,优先想到状压。
接下来是保姆级的分析。
定义状态:
标准的方式,定义二维,表示压入前 个数后情况数为 。
不熟悉状压的可以先去学板子。
初始化:
可以想到,当不压入时,这也是一种合法情况,这时令 为 即可。
状态转移:
这是本题的关键所在,应该分两种不同的情况分析。
- 当压入的是 时,这时由于其是最小数,所以一定可以将其压入序列中,此时状态 就会加二,并且压入了 个数,此时如果已经满足最大值大于 ,就直接继承 全部选定,即 的情况,否则就继承当前情况 即可。
- 反之,当压入的是 时,我们又要分类讨论,当此时的状态中,上一个数已经为 时,此时无法在上一个状态中直接压入 ,所以说此时直接继承 时的情况另开,当此时恰好满足 时,那么不用再继续更新,直接继承来自 的状态即可,否则如果不满足上述情况时,就同理要么已经大于 继承 的状态,要么就不满足不大于继承 的情况。
输出答案:
显然,输出当压入完 个数,状态为 全部选定的情况。
坑点:
- 记得取模。
- 数组一定要开够。
- 要仔细理解题意,注意细节错误。
- 千万不要抄题解。
代码公示:
CPP#include<bits/stdc++.h>
using namespace std;
const int P=1e9+7;
int n,k;
int x;
int dp[2005][(1<<11)+1];
int a[3005];
signed main(){
cin>>n>>k;
dp[0][0]=1;
for(int i=0;i<n;i++){
cin>>x;
for(int j=0;j<=(1<<k);j++){
if(x!=4){
int ni=i+1;
int nj=min((1<<k),j+2);
dp[ni][nj]=(dp[ni][nj]+dp[i][j])%P;
}
if(x!=2){
int ni=i+1;
int nj=j+4;
if(nj==(1<<k)) nj=j;
if(j&2){
nj=4;
}
else nj=min(j+4,(1<<k));
dp[ni][nj]=(dp[ni][nj]+dp[i][j])%P;
}
}
}
cout<<dp[n][(1<<k)];
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...