大师
题目链接
题目描述
建筑大师最近在跟着数学大师ljt12138学数学,今天他学了等差数列,ljt12138决定给他留一道练习题。
ljt12138首先建了n个特斯拉电磁塔,这些电塔排成一排,从左到右依次标号为1到n,第i个电塔的高度为h[i]。
建筑大师需要从中选出一些电塔,然后这些电塔就会缩到地下去。这时候,如果留在地上的电塔的高度,从左向右构成了一个等差数列,那么这个选择方案就会被认为是美观的。
建筑大师需要求出,一共有多少种美观的选择方案,答案模998244353。
注意,如果地上只留了一个或者两个电塔,那么这种方案也是美观的。地上没有电塔的方案被认为是不美观的。
输入
第一行一个正整数n。
第二行n个非负整数,第i个整数是第i个电塔的高度h[i]。
输出
输出一个整数,表示美观的方案数模998244353的值。
样例输入
8
13 14 6 20 27 34 34 41
样例输出
50
说明/提示
我们用v表示最高的电塔高度。
对于前30%的数据,n<=20。
对于前60%的数据,n<=100,v<=2000。
对于另外20%的数据,所有电塔的高度构成一个等差数列。
对于100%的数据,n<=1000,v<=20000。
题目分析
这道题就是让你求一个数列中有多少组等差数列
首先题目最后给了一个条件,如果地上只留了一个或者两个电塔,那么这种方案也是美观的,所以任意一个电塔可以构成一个等差数列,任意两个电塔也可以构成一个等差数列,如果是一个数字,那么答案就是电塔的数量,如果是两个数字的话,那么这个数列的公差就确定了,如果我们要在数列前面或者后面插入一个或多个数字,使得插入的数字之间的差值等于公差即可,也就是说我们枚举任意两个数字,那么我们就可以算出我们应该在这两个数字前插入一个多大的数字才能使这个这个数列构成等差数列
所以,我们可以用vector存下每一个值的位置,然后判断位置是在枚举两个数字的前面还是后面,在这里我们从前往后枚举,所以我们需要在两个数字的左边找到一个符合要求的数字,如果能找到,则状态转移
需要注意的是最后答案需要加上n,因为每一个电塔都可以构成一个答案
!!! 一定要注意一下电塔的高度,我就是少写了一个0,WA了一半以上的点,洛谷的数据还是蛮强的
代码如下
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 1010,mod = 998244353;
int f[N][N];
int a[N];
vector<int> p[20010];
int n;
int ans;
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
p[a[i]].push_back(i);
}
ans = n;
for(int i = 1;i <= n;i++)
for(int j = 1;j < i;j++){
f[j][i] = 1;
int k = a[j] - a[i] + a[j];
if(k >= 0 && k <= 20000 && p[k].size()){
for(auto x:p[k]){
if(x < j)
f[j][i] = (f[j][i] + f[x][j]) % mod;
}
}
ans = (ans + f[j][i]) % mod;
}
printf("%d",ans % mod);
}