原题链接: 大师
题意:给定一个长度为 n 的整数序列,每个元素的值在 [1,20000] 内,求有多少个不同的子序列可以构成等差数列。n≤1000。
不会做才来写题解加深一下印象qwq
假定状态 f[i][j] 为以第 i 个数结尾,公差为 j 的等差数列的方案数
大概可以想到转移方程为 f[i][j]=∑i−1k=1 if(h[i] - h[k] == j)
f[k][h[i]−h[k]],时间复杂度 O(n2m)
由于两个数可以唯一确定一个公差,可以枚举第 i 个数前面的每一个数,计算公差为 d=h[i]−h[j]
以第 j 个数结尾的公差为d 的等差数列,都可以把第j个数替换成第i个数,并且第 i个数和第 j 个数也能组成一个长度为 2 公差为 d 的等差数列,得状态转移方程 f[i][d]=f[i][d]+f[j][d]+1
同时新增 f[j][d]+1 个可以形成等差数列的子序列,累加到答案里
最后由于可能有公差为负数的情况,所以把数组的第二维开两倍,整体向右移动 20000 即可
时间复杂度 O(n2)
#include<cstdio>
#include<cstring>
const int N = 1010, M = 20010, mod = 998244353;
int h[N], f[N][M * 2]; // f[i][j]表示以i结尾,公差为j - M的方案数
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &h[i]);
int res = 0;
for(int i = 1; i <= n; i ++)
{
res ++;
for(int j = 1; j < i; j ++)
{
int d = h[i] - h[j] + M;
f[i][d] = (f[i][d] + f[j][d] + 1) % mod;
res = (res + f[j][d] + 1) % mod;
}
}
printf("%d", res % mod);
return 0;
}
为什么最后
res = (res + f[j][d] + 1)
还是要+ 1呢?