未来计算 4195 未来算算 2211 闪电链

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)
并且闪电链 必须满足以下要求:
  1. r[1]=1,r[k]=n,也就是说,B 的首尾必须分别是1,n.
  2. 对于任意的 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].
  3. 另外,还需要满足 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;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月半流苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值