版权声明:本文为博主原创文章,转载请预先通知博主(〃'▽'〃)。 https://blog.csdn.net/m0_37624640/article/details/82192018
Hint: ICPC 2017 Japan Tsukuba
题意:
- 给你三种圆盘,1.白色薄盘 2.黑色薄盘 3.黑色厚盘。其中白色薄盘和黑色薄盘的厚度为1,黑色厚盘的厚度为k。
- 现在给你一个高度为l的容器,让你往容器中放圆盘。有以下要求:
- 1.黑色的圆盘需要在顶部和底部。
- 2.白色圆盘上面如果有圆盘,必须为黑色圆盘;黑色圆盘上面如果有圆盘,必须为白色圆盘。
- 3.至少有一个圆盘在容器内。
- 4.容器内圆盘的高度应该<=l。
- 现在问你有几种放圆盘的方式?
做法:
- 自己用列出了k=3时的一些情况(其实列错了),然后发现了组合数(发现错了)。
- 直接两发组合数规律WA掉QAQ ……没想到这是道DP,(T▽T) 看来要好好练练DP了
- 那么DP是怎么推的呢?
- 以l = 5,k = 3为例:
- 我们dp[i][j]用表示第i层的颜色是j ,总共有黑白两种颜色,黑色为1,白色为0
- 我们定义dp[0][0] = 1。因为一开始一定是dp[1][1] = 1。我们在第一层放一个黑色圆盘的方式为1种,那么这个黑色圆盘一定是垒在白色圆盘上的,不如就假设有第0层,放的是白色圆盘,且有一个。
- 那么怎么转移呢??
- 你看,根据题意,要放黑色圆盘,那么它的下面一层一定是白色圆盘。所以第i层放黑色圆盘的方式就有
- ------> dp[i][1] = dp[i-1][0]
- 同理:dp[i][0] = dp[i-1][0]
- 不要忘记我们还有黑色厚盘,厚度为k的这一类
- 如果i>=k 我们是不是能从(i-k)这个高度的白色圆盘上直接放一个高度为k的黑色厚盘。
- 即dp[i][1] = dp[i][1]+dp[i-k][0]
- 最后我们统计dp[i][1]的值就是答案了。
AC代码:
#include<bits/stdc++.h>
#define IO ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define rep(i,s,t) for(int i = (int)(s); i <= (int)(t); i++)
#define rev(i,t,s) for(int i = (int)(t); i >= (int)(s); i--)
#define pb(x) push_back(x)
#define all(x) x.begin(),x.end()
#define sz(x) (int)(x).size()
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxm = 2e5+5;
const int maxn = 1e4+5;
const int INF = 0x3f3f3f3f;
ll c[105][105];
int main()
{
#ifdef LOCAL_FILE
freopen("in.txt","r",stdin);
#endif // LOCAL_FILE;
c[0][0] = 1;
int l,k;
cin>>l>>k;
for(int i=1;i<=l;i++)
{
c[i][1] = c[i-1][0];
c[i][0] = c[i-1][1];
if(i>=k)
{
c[i][1]+=c[i-k][0];
}
}
ll ans = 0;
for(int i=1;i<=l;i++) ans+=c[i][1];
cout<<ans<<endl;
return 0;
}
//dp[i][0] = dp[i - 1][ 1 ], dp[i][1] = dp[i - k][0] + dp[i - 1][0] 1代表黑 0代表白