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 }
View Code
原文地址:https://www.cnblogs.com/FOXYY/p/7675426.html