[LUOGU] 4933 大师

(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;
}
原文地址:https://www.cnblogs.com/sdfzhsz/p/9830141.html