实验室
题目描述:
LYK 在一幢大楼里,这幢大楼共有 n 层, LYK 初始时在第 a 层上。
这幢大楼有一个秘密实验室,在第 b 层,这个实验室非常特别,对 LYK 具有约束作用,即若 LYK 当前处于 x 层,当它下一步想到达 y 层时,必须满足|x-y|<|x-b|,而且由于实验室是不对外开放的,电梯无法停留在第 b 层。
LYK 想做一次旅行,即它想按 k 次电梯,它想知道不同的旅行方案个数有多少个。
两个旅行方案不同当前仅当存在某一次按下电梯后停留的楼层不同。
输入格式:
一行 4 个数, n,a,b,k。
输出格式:
一个数表示答案,由于答案较大,将答案对 1000000007 取模后输出。
输入样例 1
5 2 4 1
输出样例 1
2
输入样例 2
5 2 4 2
输出样例 2
2
输入样例 3
5 3 4 1
输出样例 3
0
数据范围:
对于 20%的数据 n,k<=5。
对于 40%的数据 n,k<=10。
对于 60%的数据 n,k<=500。
对于 90%的数据 n,k<=2000。
对于 100%的数据 n,k<=5000。
暴力搜索:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5010;
const int mod=1000000007;
int n,a,b,k,ans;
void dfs(int x,int y)
{
if(x==k+1)
{
ans=(ans+1)%mod;
return;
}
for(int i=1;i<=n;i++)
if(abs(y-i)<abs(y-b)&&i!=y)
dfs(x+1,i);
}
int main()
{
scanf("%d%d%d%d",&n,&a,&b,&k);
dfs(1,a);
printf("%d",ans);
return 0;
}
记忆化搜索:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5010;
const int mod=1000000007;
int n,a,b,k,ans,f[maxn][maxn];
int dfs(int x,int y)
{
if(x==k+1) return 1;
for(int i=1;i<=n;i++)
if(abs(y-i)<abs(y-b)&&i!=y)
{
if(f[x+1][i]) f[x][y]=f[x][y]+f[x+1][i];
else f[x][y]=f[x][y]+dfs(x+1,i);
}
return f[x][y];
}
int main()
{
scanf("%d%d%d%d",&n,&a,&b,&k);
f[1][a]=dfs(1,a);
printf("%d",f[1][a]);
return 0;
}
O(n^3)动规+压维
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5010;
const int mod=1000000007;
int n,a,b,k,ans,f[2][maxn];
int main()
{
scanf("%d%d%d%d",&n,&a,&b,&k);
for(int i=1;i<=n;i++)
f[k+1&1][i]=1;
for(int i=k;i>=1;i--)
{
for(int j=1;j<=n;j++)
f[i&1][j]=0;
for(int j=1;j<=n;j++)
for(int l=1;l<=n;l++)
if(abs(j-l)<abs(j-b)&&l!=j)
f[i&1][j]=(f[i&1][j]+f[i+1&1][l])%mod;
}
printf("%d",f[1][a]);
return 0;
}
优化动规
思路:
搜索–>记忆化搜索–>动规 O(n^3)–>动规 O(n^2)
dp状态
f[i][j]表示第i次停在j的方案数
倒推 边界为f[k+1][j]=1(j!=b)
因为最后可以停在除了b的所有地方
f[i][j]+=f[i+1]l
本来应该循环但超时
令x=abs(j-b)
abs(j-l)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1000000007;
const int maxn=5010;
int n,a,b,k,ans,f[2][maxn],sum[maxn];
int init()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main()
{
freopen("lab.in","r",stdin);
freopen("lab.out","w",stdout);
n=init();a=init();b=init();k=init();
for(int i=1;i<=n;i++)
{
if(i!=b)f[k+1&1][i]=1;
sum[i]=(sum[i-1]+f[k+1&1][i])%mod;
}
for(int i=k;i>=1;i--)
{
for(int j=1;j<=n;j++)
f[i&1][j]=0;
for(int j=1;j<=n;j++)
{
if(j==b) continue;
int cha=abs(j-b)-1;
int l=max(0,j-cha),r=min(n,j+cha);
if(l>r) continue;
f[i&1][j]=((sum[r]-sum[l-1])%mod+mod)%mod;
f[i&1][j]=((f[i&1][j]-f[i+1&1][j])%mod+mod)%mod;
}
for(int j=1;j<=n;j++)
sum[j]=(sum[j-1]+f[i&1][j])%mod;
}
printf("%d",f[1&1][a]);
fclose(stdin);fclose(stdin);
return 0;
}