IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【模拟赛】大难题(卡塔兰数,数位DP,进制转换) -> 正文阅读

[数据结构与算法]【模拟赛】大难题(卡塔兰数,数位DP,进制转换)

背景

国王之手不喜欢巨人 ,巨人也不喜欢国王之手,但他们有一个共同点:都不喜欢炼金师。
——Deadcells:王座之间

题面

一个阶梯状图形,第一行靠右有 n n n 个色块,第二行靠右有 n ? 1 n-1 n?1 个色块……一直到第 n n n 行。令 f ( n ) f(n) f(n) 等于用最少的矩形不重叠地刚好覆盖所有色块的方案数。

定义 V ( x ) V(x) V(x) x x x 的质因数分解中 7 的幂。

max ? i = l r V ( ( i + 1 ) f ( i ) ) \max_{i=l}^r V((i+1)f(i)) maxi=lr?V((i+1)f(i))

l ≤ r ≤ 1 0 10000 l\leq r\leq 10^{10000} lr1010000

题解

这道题,懒人是很难做出来的。

我们先分析函数 f ( n ) f(n) f(n) ,容易发现 f ( n ) f(n) f(n) 的递推式:
f ( n ) = ∑ i = 1 n f ( i ? 1 ) f ( n ? i ) f(n)=\sum_{i=1}^{n} f(i-1)f(n-i) f(n)=i=1n?f(i?1)f(n?i)

这个递推式和卡塔兰数的递推式一模一样,由于开头的几项也一样,所以 f ( n ) f(n) f(n) 就是卡塔兰数。

如果我们列出卡塔兰数的这个表达式 f ( n ) = ( 2 n n ) ? ( 2 n n ? 1 ) f(n)={2n\choose n}-{2n\choose n-1} f(n)=(n2n?)?(n?12n?) ,我们是做不出来的。所以记忆不同的一些表达式总是很有必要:
f ( n ) = ( 2 n n ) ? ( 2 n n ? 1 ) = ( 2 n n ) ? n n + 1 ? ( 2 n n ) = ( 2 n n ) n + 1 f(n)={2n\choose n}-{2n\choose n-1}={2n\choose n}-\frac{n}{n+1}\cdot {2n\choose n} =\frac{2n\choose n}{n+1} f(n)=(n2n?)?(n?12n?)=(n2n?)?n+1n??(n2n?)=n+1(n2n?)?

代进去,刚好
max ? i = l r V ( ( i + 1 ) f ( i ) ) = ? max ? i = l r V ( ( 2 i i ) ) = max ? i = l r V ( ( 2 i ) ! ) ? 2 V ( i ! ) \max_{i=l}^r V((i+1)f(i))=\\~\\ \max_{i=l}^r V\left({2i\choose i}\right)= \\\max_{i=l}^r V((2i)!)-2V(i!) i=lmaxr?V((i+1)f(i))=?i=lmaxr?V((i2i?))=i=lmaxr?V((2i)!)?2V(i!)

接下来冷静分析 V ( x ! ) V(x!) V(x!)
V ( x ! ) = ∑ i = 1 ? x 7 i ? V(x!)=\sum_{i=1} \left\lfloor \frac{x}{7^i} \right\rfloor V(x!)=i=1??7ix??

我们把 x x x 表示成 7 7 7 进制数 ∑ i = 0 a i 7 i \sum_{i=0} a_i7^i i=0?ai?7i 就好办了
V ( x ! ) = ∑ i = 0 a i 7 i ? 1 ? 1 6 = ∑ i = 0 ( a i 7 i ? 1 ? a i ) 6 = ? x / 6 ? ? ∑ i = 0 a i 6 V(x!)=\sum_{i=0} a_i\frac{7^{i-1}-1}{6}=\frac{\sum_{i=0} (a_i7^{i-1}-a_i)}{6}=\frac{\lfloor x/6\rfloor-\sum_{i=0}a_i}{6} V(x!)=i=0?ai?67i?1?1?=6i=0?(ai?7i?1?ai?)?=6?x/6??i=0?ai??

我们再令 S x = ∑ i = 0 a i S_x=\sum_{i=0}a_i Sx?=i=0?ai? ,答案式子就很直观了
max ? i = l r V ( ( 2 i ) ! ) ? 2 V ( i ! ) = max ? i = l r 2 S i ? S 2 i 6 \max_{i=l}^r V((2i)!)-2V(i!)=\max_{i=l}^r \frac{2S_i-S_{2i}}{6} i=lmaxr?V((2i)!)?2V(i!)=i=lmaxr?62Si??S2i??

由于 S i S_i Si? 是七进制下每一位的和,所以最终答案不超过两万!

最后我们可以用数位DP来解决,除了是否抵达上/下界,还要记录 2 i 2i 2i 后续是否进位,不然无法处理 S 2 i S_{2i} S2i?

由于需要进制转换,所以用压位高精的话,时间是极小常数的 O ( ∣ r ∣ 2 ) O(|r|^2) O(r2)

CODE

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 10005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
//#define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

int n,m,s,o,k;
char ll[MAXN],rr[MAXN];
const int B = 100000000;
struct it{
	vector<int> s;
	int n;
	it(){s.resize(2); s[n=1] = 0;}
	it(int x){s.resize(2); s[n=1] = x;}
	int MD(int x) {
		int as = 0;
		for(int i = n;i > 0;i --) {
			as = (as*B%x + s[i]) % x;
		}return as;
	}
	bool emp() {return n == 1 && s[1] == 0;}
};
it operator + (it a,it b) {
	int m = 0;
	for(int i = 1;i <= a.n || i <= b.n || m;i ++) {
		if(i >= a.s.size()) a.s.push_back(0);
		if(i > a.n) a.s[++ a.n] = 0;
		if(i >= b.s.size()) b.s.push_back(0);
		if(i > b.n) b.s[++ b.n] = 0;
		a.s[i] = a.s[i] + b.s[i] + m;
		if(a.s[i] > B) a.s[i] -= B,m = 1;
	}
	return a;
}
it operator * (it a,it b) {
	it c; if(a.n > b.n) swap(a,b);
	for(int i = 1;i <= a.n;i ++) {
		int m = 0;
		for(int j = 1;j <= b.n || m;j ++) {
			if(j >= b.s.size()) b.s.push_back(0);
			if(j > b.n) b.s[++ b.n] = 0;
			if(i+j-1 >= c.s.size()) c.s.push_back(0);
			if(i+j-1 > c.n) c.s[++ c.n] = 0;
			LL nm = (c.s[i+j-1] + a.s[i]*1ll*b.s[j] + m);
			m = nm/B; c.s[i+j-1] = nm%B;
		}
	}return c;
}
it operator / (it a,int b) {
	LL m = 0;
	for(int i = a.n;i > 0;i --) {
		m = m*B + a.s[i];
		a.s[i] = m / b; m %= b;
	} while(a.n > 1 && a.s[a.n] == 0) a.n --;
	return a;
}
int a[MAXN<<2],b[MAXN<<2];
int dp[MAXN<<2][2][2][2];
int main() {
	freopen("dingdingcar.in","r",stdin);
	freopen("dingdingcar.out","w",stdout);
	it L,R;
	scanf("%s",ll + 1);
	n = strlen(ll + 1);
	scanf("%s",rr + 1);
	m = strlen(rr + 1);
	for(int i = 1;i <= n;i ++) L = L * it(10) + it(ll[i]-'0');
	for(int i = 1;i <= m;i ++) R = R * it(10) + it(rr[i]-'0');
	n = 0; m = 0;
	while(!L.emp()) a[++ n] = L.MD(7),L = L/7;
	while(!R.emp()) b[++ m] = R.MD(7),R = R/7;
	int le = max(n,m);
	for(int s = 0;s < 2;s ++) {
		for(int o = 0;o < 2;o ++) {
			for(int k = 0;k < 2;k ++) {
				dp[le+2][s][o][k] = -0x3f3f3f3f; // 44 65
			}
		}
	}
	dp[le+2][0][0][0] = 0;
	for(int i = le+1;i > 0;i --) {
		for(int s = 0;s < 2;s ++) {
			for(int o = 0;o < 2;o ++) {
				for(int k = 0;k < 2;k ++) {
					dp[i][s][o][k] = -0x3f3f3f3f;
				}
			}
		}
		for(int s = 0;s < 2;s ++) {
			for(int o = 0;o < 2;o ++) {
				int nl = (s ? 0:a[i]),nr = (o ? 6:b[i]);
				for(int x = nl;x <= nr;x ++) {
					bool k1 = ((x<<1)>=7 ? 1:0),k2 = ((x<<1|1)>=7 ? 1:0);
					bool A = (s || x > a[i]),B = (o || x < b[i]);
					dp[i][A][B][0] = max(dp[i][A][B][0],dp[i+1][s][o][k1] + x*2 - (x*2%7));
					dp[i][A][B][1] = max(dp[i][A][B][1],dp[i+1][s][o][k2] + x*2 - ((x<<1|1)%7));
				}
			}
		}
	}
	int ans = 0;
	for(int s = 0;s < 2;s ++) {
		for(int o = 0;o < 2;o ++) {
			ans = max(ans,dp[1][s][o][0]);
		}
	}
	ans /= 6;
	AIput(ans,'\n');
	return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:27:37  更:2022-04-06 23:30:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:30:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码