【题解】LuoGu4933:大师

原题传送门
其实这道题很简单
如果想到把公差设计到状态里面去,难度就急剧下降了
d p i , j dp_{i,j} dpi,j表示以 a i a_i ai结尾,且公差为 j j j的等差数列有多少个
所以我们花 O ( n v ) O(nv) O(nv)的时间枚举状态,再花 O ( n ) O(n) O(n)的时间转移
d p i , j + = d p k , j + 1 ( a k + j = a i ) dp_{i,j}+=dp_{k,j}+1(a_k+j=a_i) dpi,j+=dpk,j+1(ak+j=ai)
这样我们就拿到了60分的好成绩
但是其实根本不必枚举公差是多少
对于一个公差 d d d,若不存在 a x , a y a_x,a_y ax,ay,使得 a x + d = a y a_x+d=a_y ax+d=ay,这个公差是没有意义的,为了处理这个冗余,我们直接枚举两个数,由这两个数确定公差
d p i , a i − a j + = d p j , a i − a j + 1 dp_{i,a_i-a_j}+=dp_{j,a_i-a_j}+1 dpi,aiaj+=dpj,aiaj+1
这样 O ( n 2 ) O(n^2) O(n2)就解决了
如何统计答案呢,这里需要和 d p dp dp数组一起更新
a n s + = d p j , a i − a j + 1 ans+=dp_{j,a_i-a_j}+1 ans+=dpj,aiaj+1
最终输出 a n s + n ans+n ans+n,因为每个数单独一个也算

Code:

#include 
#define maxn 40010
#define maxm 1010
using namespace std;
const int qy = 998244353;
int n, a[maxn], dp[maxm][maxn], ans;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

int main(){
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	int p = 20000;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j < i; ++j){
			(dp[i][a[i] - a[j] + p] += dp[j][a[i] - a[j] + p] + 1) %= qy;
			(ans += dp[j][a[i] - a[j] + p] + 1) %= qy;
		}
	printf("%d\n", (ans + n) % qy);
	return 0;
}

你可能感兴趣的:(题解,LuoGu,DP,题解,LuoGu,DP)