首页 > 其他分享 >【YBT2023寒假Day10 B】随机游走(记忆化搜索)

【YBT2023寒假Day10 B】随机游走(记忆化搜索)

时间:2023-02-20 01:44:04浏览次数:68  
标签:... return int mo YBT2023 re 寒假 Day10 addex

随机游走

题目链接:YBT2023寒假Day10 B

题目大意

有 n 个点排成环,你一开始在 1 号点,每次可以等概率选择左边跳两格,左边跳一格,右边跳一格,右边跳两格。
走到一个走过的点就停止。
问你走的期望步数。

思路

首先一个暴力的 DP 是有当前点和所有点是否到过这两个状态。
不过会发现特殊得到行动方式使得很多状态是不存在的。

考虑思考怎样才会是合法的状态。
考虑到最多跳两格,那当存在一个 \(11\) 的部分的时候而且你不站在这两个点上,那你是不能跨越它的。

那我们考虑会不会存在一些不能到的地方,也就是存在 \(11X...X11\) 而且当前你不在这些点上,那就可以直接变成 \(111...111\)。
那也就是这两个是等价的,那场上不会存在两对 \(11\) 中间有 \(0\),那就是一个 \(X...X1...1X...X\) 的形式。
还有一个点就是两边的 \(X...X\) 其实也很固定,因为你只有跳两格的情况,那就是 \(...101011...11010101...\)

那考虑根据这个形式来统计一下状态数。
那我们就枚举 \(11...11\) 的长度,再枚举左右 \(01\) 串的长度,在是当前点的位置,那总状态数是 \(n^4\) 的,记搜转移就可以了。

代码

#include<map>
#include<cstdio>

using namespace std;

const int N = 80;
int n, mo, inv4, ans;
map <pair<int, __int128>, int> rem;
__int128 one = 1;

int add(int x, int y) {return x + y >= mo ? x + y - mo : x + y;}
int dec(int x, int y) {return x < y ? x - y + mo : x - y;}
int mul(int x, int y) {return 1ll * x * y % mo;}
int addex(int x, int y, int z) {return x + y >= z ? x + y - z : x + y;}
int decex(int x, int y, int z) {return x < y ? x - y + z : x - y;}
int ksm(int x, int y) {
	int re = 1;
	while (y) {
		if (y & 1) re = mul(re, x);
		x = mul(x, x); y >>= 1;
	}
	return re;
}

__int128 work(int fr, __int128 s) {
	int a = -1, b = -1;
	for (int i = addex(fr, 1, n); i != decex(fr, 1, n); i = addex(i, 1, n)) {
		int j = addex(i, 1, n);
		if (((s >> i) & 1) && ((s >> j) & 1)) {
			if (a == -1) a = i;
			b = i;
		}
	}
	for (int i = a; i != b; i = addex(i, 1, n)) {
		s |= (one << i);
	}
	return s;
}

int dfs(int now, __int128 s) {
	if ((s >> now) & 1) return 0;
	s |= (one << now); s = work(now, s);
	if (rem[make_pair(now, s)]) return rem[make_pair(now, s)];
	return rem[make_pair(now, s)] = add(1, mul(inv4, add(add(dfs(addex(now, 1, n), s), dfs(addex(now, 2, n), s)), add(dfs(decex(now, 1, n), s), dfs(decex(now, 2, n), s)))));
}

int main() {
	freopen("walk.in", "r", stdin);
	freopen("walk.out", "w", stdout);
	
	scanf("%d %d", &n, &mo); inv4 = ksm(4, mo - 2);
	if (n == 1) {printf("1"); return 0;}
	printf("%d", dfs(0, 0));
	
	return 0;
} 

标签:...,return,int,mo,YBT2023,re,寒假,Day10,addex
From: https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day10_B.html

相关文章

  • 【YBT2023寒假Day10 A】集合比较(数学)(启发式分裂)
    集合比较题目链接:YBT2023寒假Day10A题目大意给你一个长度为n的排列p,定义两个大小为n不可重集合的比较方式是先比较各自第p1小的元素,如果相同比p2,以此类推。给......
  • 寒假学习总结
    这个作业属于哪个课程班级这个作业要求在哪里作业的要求这个作业的目标对寒假学习的总结寒假学习总结一、回顾在本次寒假的学习当中,收益颇丰,每次作业......
  • day10
    变量变量就是可变化的量Java是强类型语言,每个变量必须声明其类型Java变量是程序中最基本的存储单位(变量名,变量类型和作用域)注意:每个变量都有类型,类型可以是基本类型,......
  • 寒假训练第六周
    寒假训练第六周第一天蓝桥杯训练斐波拉契数组大意:给定数组A,为最少修改几个元素后,数组A会变成一个斐波拉契数组。思路:斐波那契数组在第 30 项左右就超过 1e6了。......
  • B - Fedya and Maths 【GDUT_22级寒假训练专题五】
    B-FedyaandMaths原题链接思路找到规律发现答案以4为周期循环如果被4整除那么答案则为4,否则答案为0疑难一个长度为\(10^5\)的数怎么对4进行取模运算?分别取模如:......
  • 寒假学习记录
    这个作业属于哪个课程<班级链接>这个作业要求在哪里 <作业要求>这个作业的目标<寒假学习记录>一、对寒假的回顾尚可的点:首先在完成了在结束六级一轮......
  • 寒假总结
    这个作业的目标<学习内容的系列记录>这个作业属于哪个课程计算机导论这个作业要求在哪里https://edu.cnblogs.com/campus/fzzcxy/2023learning/homework/129......
  • F - 树状数组 2【GDUT_22级寒假训练专题五】
    F-树状数组2原题链接思路在树状数组1中我们可以得知单点修改,区间查询(区间和)对原数组进行单点修改,对区间和进行树状数组维护利用差分和前缀和我们可以推导出区......
  • E - 树状数组 1【GDUT_22级寒假训练专题五】
    E-树状数组1原题链接题意已知一个数列,你需要进行下面两种操作:将某一个数加上\(x\)求出某区间每一个数的和lowbit函数定义一个函数\(f=lowbit(x)\),这个函......
  • 寒假学习总结
    这个作业的目标<学习内容的系列记录>这个作业属于哪个课程计算机导论这个作业要求在哪里https://www.bilibili.com/video/BV1EW411u7th/?spm_id_from=333.33......