首页 > 其他分享 >ABC275D-Yet-Another-Recursive-Function题解

ABC275D-Yet-Another-Recursive-Function题解

时间:2023-03-01 16:22:05浏览次数:61  
标签:Function ABC275D return int 题解 hp long ss swap

题目传送门

题意:定义一个 \(\mathbb{N}\to\mathbb{N}\) 的函数 \(f(x)=\begin{cases}1&x=0\\f(\lfloor\frac{x}{2}\rfloor)+f(\lfloor\frac{x}{3}\rfloor)&\text{otherwise}\end{cases}\),求 \(f(n)\)。\(n\le 10^{18}\)。

很容易想到暴力求解,形成 \(\log(n)\) 层的二叉树,复杂度为 \(O(n)\),无法通过。

做法 1

注意到,有 \(\lfloor\frac{\lfloor\frac{n}{2}\rfloor}{3}\rfloor=\lfloor\frac{\lfloor\frac{n}{3}\rfloor}{2}\rfloor\),所以实际有用的状态数只有 \(\log^2 n\) 个(每层比上一层增加一个状态)。于是可以记忆化搜索,用 map 当 DP 数组即可。

By cxm1024

#include<bits/stdc++.h>
using namespace std;
map<long long,long long> m;
long long solve(long long x) {
	if(m[x]) return m[x];
	return m[x]=solve(x/2)+solve(x/3);
}
signed main() {
	long long n;
	scanf("%lld",&n);
	m[0]=1;
	printf("%lld\n",solve(n));
	return 0;
}

做法 2

可以考虑问题转化为:\(n\) 每次除以二或除以三,问有多少种操作序列能到 \(0\),然后用组合数求解即可。我们枚举用了 \(i\) 次除以二,再算出此时还需要的除以三的次数 \(j\),计算 \(\binom{i+j}{i}\) 即可。

By ygussany

#include <stdio.h>

typedef struct List {
	struct List *next;
	long long v, ans;
} list;

#define HASH 1000003
const int H_Mod = HASH;

int hn = 0;
list *hash[HASH] = {}, hd[1000000];

long long recursion(long long N)
{
	if (N == 0) return 1;

	int h = N % H_Mod;
	list *hp;
	for (hp = hash[h]; hp != NULL; hp = hp->next) if (hp->v == N) return hp->ans;
	hp = &(hd[hn++]);
	hp->v = N;
	hp->ans = recursion(N / 2) + recursion(N / 3);
	return hp->ans;
}

long long comb[61][61];

long long solve(long long N)
{
	int k, l;
	long long X, ans = 2;
	for (k = 1, X = 2; X * 2 <= N; k++, X <<= 1);
	for (l = 0; k > 0; ) {
		k--;
		X >>= 1;
		while (X * 3 <= N) {
			l++;
			X *= 3;
		}
		ans += comb[k+l][k] + ((X * 2 > N)? comb[k+l][k]: 0);
	}
	return ans;
}

int main()
{
	long long N;
	scanf("%lld\n", &N);
	if (N == 0) {
		printf("1\n");
		return 0;
	} else if (N == 1) {
		printf("2\n");
		return 0;
	}

	int i, j;
	for (i = 1, comb[0][0] = 1; i <= 60; i++) for (j = 1, comb[i][0] = 1, comb[i][i] = 1; j < i; j++) comb[i][j] = comb[i-1][j-1] + comb[i-1][j];
	printf("%lld\n", solve(N));
	fflush(stdout);
	return 0;
}

做法 3

与做法 1 类似,不使用记忆化搜索,改为预处理出所有状态(离散化),然后直接 DP。

#include<stdio.h>
long long int h[1000006], l;
int comp_h(long long int a, long long int b)
{
	if (h[a] < h[b])
		return 1;
	else
		return -1;
}
void swap_h(long long int a, long long int b)
{
	long long int f = h[a];
	h[a] = h[b];
	h[b] = f;
	return;
}
void push(long long int ne)
{
	h[l] = ne;
	long long int p = l;
	l++;
	for (; p > 0; p = (p - 1) / 2)
		if (comp_h((p - 1) / 2, p) > 0)
			swap_h((p - 1) / 2, p);
	return;
}
long long int pop()
{
	l--;
	swap_h(0, l);
	long long int p = 0;
	for (;;)
	{
		if (2 * p + 2 < l)
		{
			if (comp_h(2 * p + 1, 2 * p + 2) > 0)
			{
				if (comp_h(p, 2 * p + 2) > 0)
					swap_h(p, 2 * p + 2);
				p = 2 * p + 2;
			}
			else
			{
				if (comp_h(p, 2 * p + 1) > 0)
					swap_h(p, 2 * p + 1);
				p = 2 * p + 1;
			}
		}
		else if (2 * p + 1 < l)
		{
			if (comp_h(p, 2 * p + 1) > 0)
				swap_h(p, 2 * p + 1);
			p = 2 * p + 1;
		}
		else
			break;
	}
	return h[l];
}
long long int s[1000006], v[1000006], ss;
long long int fined(long long int x)
{
	long long int min, mid, max;
	min = -1;
	max = ss;
	while (max - min > 1)
	{
		mid = (max + min) / 2;
		if (s[mid] < x)
			max = mid;
		else
			min = mid;
	}
	return v[min];
}
int main()
{
	long long int n;
	scanf("%lld", &n);
	long long int i;
	s[0] = n;
	ss = 1;
	l = 0;
	push(n / 2);
	push(n / 3);
	while (l > 0)
	{
		i = pop();
		if (s[ss - 1] == i)
			continue;
		s[ss] = i;
		ss++;
		push(i / 2);
		push(i / 3);
	}
	v[ss - 1] = 1;
	for (i = ss - 2; i >= 0; i--)
		v[i] = fined(s[i] / 2) + fined(s[i] / 3);
	printf("%lld\n", v[0]);
	return 0;
}

标签:Function,ABC275D,return,int,题解,hp,long,ss,swap
From: https://www.cnblogs.com/cxm1024/p/17168397.html

相关文章

  • CF71D-Solitaire题解
    题目传送门题意:一副扑克牌由54张牌组成,包括52张基本牌和两张“王”。在本题中每张牌用两个字符表示:对于基本牌,第一个字符为点数,有'2''3''4''5''6''7''8''9......
  • CF118C-Fancy-Number题解
    题目传送门题意:有一个\(n\)位的数字串,每位为\(0-9\)。每次操作可以更改一位的数字,代价为新旧两位数字之差。问使字符串存在某一个数的出现次数超过\(k\)的最小代价......
  • CF15D-Map题解
    题目传送门题意:有一个\(n\timesm\)的矩阵,每个格子有一个权值。每次操作会选择一个\(x\timesy\)的矩形区域,花费为“每个位置的权值减去最小权值”之和,区域之间不能......
  • CF杂题题解
    129B.StudentsandShoelaces题意:一个\(n\)个点\(m\)条边的无向图,每一轮删去所有度数为\(1\)的点,问删几轮停止。暴力模拟每一轮即可,每次删点更新邻居度数。{%......
  • CSP-J2022-C-逻辑表达式题解
    题意:给你一个由0、1、&、|、(、)组成的字符串,保证是一个合法的逻辑表达式。其中括号优先级最高,与运算优先级高于或运算,同级之间从左到右算。定义一次短路为,或运算的左边......
  • Gym100078H-History-of-Football题解
    题目传送门题意:有\(n\)支球队,每两支球队之间都会进行一场较量,赢者积\(3\)分,输者积\(0\)分,如果平局则各积\(1\)分。给出每支球队的最终积分,求方案数。\(n\le8\)......
  • Gym100753D-Carpets题解
    题目传送门题意:有一个\(H\timesW\)的地板和\(n\)个矩形地毯,问是否能不重不漏地填满地板。\(H,W\le100,n\le7\)。考虑朴素的搜索,每次考虑最左上角的没填的位置,枚......
  • Gym100825C-KenKen-You-Do-It题解
    题目传送门题意:在一个矩阵上选中了若干个格子,保证连通。你需要在这些格子中填数,使得:每行每列不能重复,且这些数进行给定运算(可以认为只有加法和乘法)的结果为给定的数值。......
  • Gym100959I-Robots题解
    题意:平面直角坐标系上有\(n\)个机器人,每个机器人有一个上下左右之一的方向,初始所有机器人静止。在第\(0\)秒,你让第一个机器人开始朝它的方向移动,速度为每秒一个单位。......
  • Gym101252B-Kakuro题解
    题目传送门题意:有一个矩阵,每个格子为黑色或白色。你需要向白色格子中填\(1\sim9\)的整整睡。从某一个黑色格子的右侧往右连续的一段极长的白色格子被称为一个run,往下......