PS:如果读过题了可以跳过题目描述直接到题解部分
提交链接1:未来计算 4195 闪电链
提交链接2:未来算算 2211 闪电链
题目
题目背景
用好三维立体混元劲儿,
才能打出松活弹抖闪电链。
题目描述
有一个长度为 n 的序列 A ={a[1],a[2]…a[n]} 。并且给出了一个整数 h 。
闪电链 B 是序列 A 的一个下标序列:B={r[1],r[2]…r[k]},(1≤r[1]<r[2]<…<r[k]≤n)
并且闪电链 必须满足以下要求:
- r[1]=1,r[k]=n,也就是说,B 的首尾必须分别是1,n.
- 对于任意的 2≤i<k,r[i+1]-r[i]的值满足以下条件之一:r[i+1]-r[i]=a[r[i]] 或者 r[i+1]-r[i]=r[i]-r[i-1].
- 另外,还需要满足 r[2]-r[1]=a[r[1]] 或者 r[2]-r[1]=h.
有多少个不同的闪电链序列 B 满足以上条件?答案对
998244353
取模。
由于下标序列本身有序,两个下标序列不同,当且仅当他们的含有的数字不同。
输入格式
第一行,正整数 n,h。
接下来一行,n 个正整数 a[i] 。
输出格式
输出闪电链的个数。答案对998244353取模。
样例
输入
5 1
2 3 2 4 3
输出
4
提示
样例解释
{1,2,5}
{1,3,5}
{1,2,3,4,5}
{1,2,3,5}
数据范围
对于
15%的数据,满足 n≤18.
对于
30%的数据,满足 n≤10^3.
另有
20%的数据,满足 a[i]≤300.
另有
20%的数据,满足 10^3≤a[i].
对于100%的数据,满足 2≤n≤10^5,1≤h,a[i]≤n-1.
题解
暴力能过,注意去重!!!
简单说,就是直接更新通过“等差数列”当前能到的所有点的情况数。
去重主要是要注意会不会现在的和现在能到的数的“等差间距”相等,这时情况会算重,直接break掉就可以了。
代码实现
//未来计算 4195 未来算算 2211 闪电链
#include<iostream>
#include<cstdio>
using namespace std;
const int mo=998244353;
int n;
int h;
int a[100010];
long long b[100010];
int main(){
cin>>n>>h;
b[1]=1;
b[h+1]=1;
for(int i=1;i<=n;++i){
cin>>a[i];
}
if(h!=a[h+1]){
for(int i=1+(h<<1);i<=n;i+=h){
++b[i];
if(a[i]==h){
break;
}
}
}
++b[a[1]+1];
if(h!=a[1]&&a[1]!=a[a[1]+1]){
for(int i=(a[1]<<1)+1;i<=n;i+=a[1]){
++b[i];
if(a[i]==a[1]){
break;
}
}
}
for(int i=min(h+1,a[1]+1);i<=n;++i){
for(int j=i+a[i];j<=n;j+=a[i]){
b[j]=((b[j]+b[i])%mo+mo)%mo;
if(a[j]==a[i]){
break;
}
}
}
printf("%lld",(b[n]%mo+mo)%mo);
return 0;
}