BZOJ[1925] [Sdoi2010]地精部落
很难理解的一个DP
首先先说明两个状态数组,f[i][j]表示当前序列的长度为i,最后一位是第j小,且第i位为山谷的方案数,同理g[i][j]表示f[i][j]表示当前序列的长度为i,最后一位是第j小,且第i位为山峰的方案数;
那么f就是能从g转移过来,
那么f[i][j]就等于g[i-1][k] (j<=k<=i-1);然后考虑优化,可以想象把整段山脉倒过来,那么f[i][j]与g[i][i-j+1]的方案书是一样的,那么f[i][j]就等于f[i-1][k](1<=k<=i-j);
然后我一直不理解的是,这里的j只是表示一个相对的大小关系,当他联系到具体的数字的时候,不用考虑第j小的数字到底要选哪个么? 是不是要乘一个 j... 什么的东西,
其实这个相对关系可以说是唯一的,他只是表示满足当前大小关系的状态的方案数,而不是满足这种关系具体有多少可能,当转移到最后的n的时候,第j小时哪一个数字就是确定的,然后从之前转移过来的每一种状态也都就是确定的,也就是之前说的唯一的;
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 typedef long long LL; 9 int n; 10 LL mod; 11 LL f[3][4300]; 12 int main(){ 13 // freopen("a.in","r",stdin); 14 scanf("%d%lld",&n,&mod); 15 f[1][1]=1; int rol=0; 16 for(int i=2;i<=n;i++){ 17 memset(f[rol],0,sizeof(f[rol])); 18 LL sum=0; 19 for(int j=i-1;j>=1;j--){ 20 sum=(sum+f[rol^1][i-j])%mod; 21 // cout<<"sim== "<<sum<<endl; 22 f[rol][j]=sum; 23 } 24 rol^=1; 25 } 26 LL ans=0; 27 for(int i=1;i<=n;i++){ 28 ans=(ans+f[rol^1][i])%mod; 29 } 30 ans=(ans*2)%mod; 31 cout<<ans<<endl; 32 }