(Orz) (ljt12138!)
设状态(f[i][j])表示以(i)为结尾,公差为(j)的长度大于(1)的数列有几个。
然后转移方程就很好想了。
(k=H[i]-H[j])
(f[i][k]=sumlimits_{j=1}^{i-1} (f[j][k]+1))
之前的等差数列加上最后那个数形成新的等差数列,再加上((i,j))。
每次枚举到一个(f[j][k])就把答案加上这个数,表示这个数列后面续接上(i)的贡献,但是这样的话长度为1和2的序列就需要单独计算了。
(希望没有出锅,欢迎拍砖)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=1005,base=20000,mod=998244353;
int f[1005][40005],n,h[N],ans;
inline void add(int &x,int y) {
if(x+y>=mod) return x=x+y-mod,void();
x=x+y;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
for(int i=1;i<=n;i++) {
add(ans,i);//len=1 or 2
for(int j=1;j<i;j++) {
int tp=h[i]-h[j];
add(ans,f[j][tp+base]);
add(f[i][tp+base],f[j][tp+base]+1);
}
}
cout<<ans<<endl;
return 0;
}