洛谷 P4933 大师(dp)
传送门
解题思路
设dp[i][j]表示选出了第i个电塔,上一个选出的是第j个电塔的方案数。
枚举i,j,转移方程为:
找一个k,使得h[k],h[j],h[i]构成等差数列,并且k<j。
dp[i][j]+=dp[j][k];
对于确定的i,j,h[k]是确定的,所以我们可以用vector a[i]的高度为i的编号,k即为枚举a[h[k]]里的元素。
为了防止快乐的RE,
要判断计算出的h[k]是否<0或者>=maxv。
时间复杂度不太会算,看起来像是在O(n^2)到O(n^3)之间,貌似重复元素个数不同时间不同……
有大佬知道的麻烦在评论区留言,万分感谢~
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 #include<vector> 7 using namespace std; 8 const int maxn=1005; 9 const int maxv=20005; 10 const int mod=998244353; 11 int n,h[maxn],dp[maxn][maxn],ans; 12 vector<int> a[maxv]; 13 int main() 14 { 15 cin>>n; 16 ans=n; 17 for(int i=1;i<=n;i++) cin>>h[i]; 18 for(int i=1;i<=n;i++) { 19 for(int j=1;j<i;j++){ 20 dp[i][j]=1; 21 int d=h[i]-h[j]; 22 if(h[j]-d<0||h[j]-d>=maxv){ 23 ans=(ans+1)%mod; 24 continue; 25 } 26 for(int k=0;k<a[h[j]-d].size();k++){ 27 if(a[h[j]-d][k]>=j) break; 28 else dp[i][j]=(dp[i][j]+dp[j][a[h[j]-d][k]])%mod; 29 } 30 ans=(ans+dp[i][j])%mod; 31 } 32 a[h[i]].push_back(i); 33 } 34 cout<<ans; 35 return 0; 36 }
//明天还上课,困死了,睡觉睡觉…………