D. Game on Axis 【思维(1900


Problem - D - Codeforces

题意:n个数字,规定跳跃规则为 ,每次从1出发,可以执行一次操作()问可能的情况有几种;

 

分析:很好想到建图,把不在范围内的路径全连到 n+1 点上,然后分类讨论。

 

如果点 1 可以走到终点 n+1,那么 1)不在 1 路径上的点随便怎么样都行,2)其他的点不能走到他的后继(这里我们发现从 n+1 反向建边,x+1个点,x条边,必然是一个树,所以反向树形DP一下,减去子树即可)

如果 1 不能走到终点 n+1 ,分别思考 1 成链和成环 的情况,发现都可以总结为考虑 1 往前的路径的点,这些点1)要不超出本身,2)要不连到树上;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 15;
const int mo = 998244353;
#define pb push_back
#define pii pair<int,int>
#define ft first
#define sd second
#define ffor(i,a,b,c) for(int i=(a);i<(b);i+=(c))
#define For(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
#define rfor(i,a,b,c) for(int i=(a);i>(b);i-=(c))
#define Rfor(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
#define all(x) (x).begin(), (x).end()
#define debug1(x) cerr<<"! "<<x<<endl;
#define debug2(x,y) cerr<<"#  "<<x<<" "<<y<<endl;

void slv() {
	int n; cin >> n;
	vector<vector<int>>E(n + 2), R(n + 2);
	vector<int>a(n + 1);
	For(i, 1, n, 1) {
		cin >> a[i];
		int v = a[i] + i;
		if (v < 1 || v > n) v = n + 1;
		E[i].pb(v);
		R[v].pb(i);
	}
	vector<int>vis(n + 2), sz(n + 2), rvis(n + 2);
	function<void(int)>dfs = [&](int u) {
		sz[u] = 1;
		for (auto v : R[u]) {
			vis[v] = 1;
			dfs(v);
			sz[u] += sz[v];
		}
	};
	auto cal = [&](int k) {//超出范围的点,后来才发现是个定值
		return n + 1;
	};
	dfs(n + 1);
	function<int(int)>dig = [&](int u) {
		int sm = 0; rvis[u] = 2;
		for (auto v : E[u])if (!rvis[v]) {
				sm++;
				sm += dig(v);
			}
		return sm;
	};
	int sm = dig(1);
	if (vis[1]) {
		ll ans = 0;
		For(i, 1, n, 1) {
			if (rvis[i] == 2) {
				ans += cal(i) + sz[n + 1] - sz[i] - 1;
			} else {
				ans += 2 * n + 1;
			}
		}
		cout << ans << '\n';
	} else {
		vector<int>tmp;
		For(i, 1, n, 1) if (rvis[i] == 2) {
			tmp.pb(i);
		}
		ll ans = 0;
		for (auto k : tmp) {
			ans += cal(k);
			ans += sz[n + 1] - 1;
		}
		cout << ans << '\n';
	}
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int t; cin >> t;
	while (t--) {
		slv();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值