http://codeforces.com/problemset/problem/432/D
题目大意:
给出一栋n层的楼,初始在a层,b层不能去,每次走的距离必须小于当前位置到b的距离,问用电梯来回乱跑得到的序列有多少种。
思路:发现在a的这一侧永远不会到b的另一侧去,因此我们拆开来,只保留a所在的这边,dp:
f[i][j]=Σf[i-1][j] (1<=j<=i+i-1)
然后我们记录前缀和,一边算出sum[1,i-1],另一边用两个指针l,r,每次r移动2,l移动1,算出sum[l,r]
PS:之前用l和r还一边走一边修改真是太傻比了
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<iostream> #define ll long long const ll Mod=1000000007; ll f[2][10005],sum[200005]; int n,a,b,K,len,pos; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } ll query(int l,int r){ if (r>len) r=len; return (((sum[r]-sum[l-1])%Mod)+Mod)%Mod; } int main(){ n=read();a=read();b=read();K=read(); if (a<b) len=b-1,pos=b-a;else len=n-b,pos=a-b; for (int i=1;i<=len;i++) f[0][i]=1; for (int i=1;i<=K;i++){ ll cnt=0; for (int j=0;j<=len;j++) f[i%2][j]=0; sum[0]=0; for (int j=1;j<=len;j++) sum[j]=(sum[j-1]+f[(i-1)%2][j])%Mod; for (int j=1;j<=len;j++){ f[i%2][j]=(f[i%2][j]+cnt)%Mod; cnt=(cnt+f[(i-1)%2][j])%Mod; } cnt=0; int r=len+len-1,l=len+1; for (int j=len;j>=1;j--){ f[i%2][j]=(f[i%2][j]+query(l,r))%Mod; r-=2; l--; } } printf("%I64d ",f[K%2][pos]); return 0; }