Gym - 101612L Little Difference(二分)

本文深入探讨了一道涉及数列生成的算法题,题目要求生成所有符合条件的数列,其中数列内所有项相乘等于给定的大数n,且任意两项之差不超过1。文章分析了特殊情况和一般情况下的解决策略,提出了基于二分查找和枚举的高效算法,复杂度为O((logn)^3)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://vjudge.net/problem/Gym-101612L

题目大意:给出一个n,1 <= n <= 10^18,生成所有满足条件的数列,这些数列需要满足数列内的所有项相乘等于n,数列内的任意两项只差必须小于等于1。若这样的数列是有限个,全部输出,否则输出-1。

首先这题特别坑,光题意就看了好久好久好久……看到自闭,最后终于看懂,然后想了一会发现能做,接下来就陷入无限的找bug中,最后发现有一个特例没判断。不扯了,看题。

 

分析:首先我们可以很轻易的知道 1 应该是输出 -1 ,还可以发现 2 也是 -1,因为可以有这么个数列:2,1,1,……,1 这是无限个的,所以也是 -1 ,还有一个特别坑的地方,所有的 2 的次幂都是 -1,道理和 2 一样,但是不容易想到这个特例。

 

现在是对于一般情况,我们看到数的范围很大,n大约在 2^63 次方以内,而对于一组合法的数列只有两种可能:1,只由 a 组成。2,只由 a 和 a+1 组成。这样一来我们想一下,对于一个合法的数列,这个数列的长度是这个数列独有的,不可能有另一个合法的数列和这个长度一样。

 

现在我们假设知道了这个数列长度,我们可以二分出来这个 a,有了这个a,我们就可以生成这个合法的数列。

 

我们怎么二分这个a呢?我们枚举数列的长度 k ,若在这个长度下有一个合法的数列,那么一定有 a^i * (a+1)^k-j == n,这个a怎么找呢,二分找 a^k 小于等于 n 又最接近 n 的 a,a可能的取值只有这一个,那么数列的另一项也就出来了,a+1

 

我们前面是基于枚举的数组长度下有一个合法的数列这个条件下二分出来的 a ,那我们怎么判断这个 a 是否合法呢?我们已经知道如果合法必须满足 a^i * (a+1)^k-j == n ,那么我们可以枚举这个 i ,那么 k-i 就是 a+1 的系数,这样一来我们就可以判断是否合法了。

 

不难算出上述算法在的复杂度是O((logn)^3),最坏情况下 63^3 ,妥妥的。。。

 

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 LL n;
 7 
 8 bool check(LL a, int b) {
 9     LL ans = 1;
10     for(int i = 1; i <= b; ++i) {
11         if(n/ans >= a) ans *= a;
12         else return false;
13     }
14     return true;
15 }
16 
17 bool judge(int a, LL b, int c, LL d) {
18     LL ans = 1;
19     for(int i = 1; i <= a; ++i) {
20         if(n/ans >= b) ans *= b;
21         else return false;
22     }
23     for(int i = 1; i <= c; ++i) {
24         if(n/ans >= d) ans *= d;
25         else return false;
26     }
27     if(ans == n) return true;
28     return false;
29 }
30 
31 LL ANS[100][100];
32 int tot;
33 void addans(int a, LL b, int c, LL d) {
34     LL& len = ANS[tot][0];
35     for(int i = 1; i <= a; ++i) ANS[tot][++len] = b;
36     for(int j = 1; j <= c; ++j) ANS[tot][++len] = d;
37     tot++;
38 }
39 
40 int main() {
41     freopen("little.in", "r", stdin);
42     freopen("little.out", "w", stdout);
43 
44     scanf("%lld", &n);
45 
46     // 如果n是2的次幂,那么就是输出-1
47     LL m = n;
48     while(m%2 == 0) m/=2;
49     if(m == 1) {
50         printf("-1\n");
51         return 0;
52     }
53 
54     for(int len = 1; len <= 64; ++len) {
55         LL l = 2, r = 1e18, ans = -1;
56         while(l <= r)  {
57             LL mid = (l+r)/2;
58             if(check(mid, len)) {
59                 ans = mid;
60                 l = mid+1;
61             }else {
62                 r = mid-1;
63             }
64         }
65 
66         if(ans == -1) break;
67 
68         for(int i = 1; i <= len; ++i) {
69             if(judge(i, ans, len-i, ans+1))
70                 addans(i, ans, len-i, ans+1);
71         }
72     }
73     printf("%d\n", tot);
74     for(int i = 0; i < tot; ++i) {
75         printf("%lld", ANS[i][0]);
76         for(int j = 1; j <= ANS[i][0]; ++j) printf(" %lld", ANS[i][j]);
77         printf("\n");
78     }
79 }
View Code

 

转载于:https://www.cnblogs.com/DynastySun/p/9671961.html

内容概要:本文介绍了多种开发者工具及其对开发效率的提升作用。首先,介绍了两款集成开发环境(IDE):IntelliJ IDEA 以其智能代码补全、强大的调试工具和项目管理功能适用于Java开发者;VS Code 则凭借轻量级和多种编程语言的插件支持成为前端开发者的常用工具。其次,提到了基于 GPT-4 的智能代码生成工具 Cursor,它通过对话式编程显著提高了开发效率。接着,阐述了版本控制系统 Git 的重要性,包括记录代码修改、分支管理和协作功能。然后,介绍了 Postman 作为 API 全生命周期管理工具,可创建、测试和文档化 API,缩短前后端联调时间。再者,提到 SonarQube 这款代码质量管理工具,能自动扫描代码并检测潜在的质量问题。还介绍了 Docker 容器化工具,通过定义应用的运行环境和依赖,确保环境一致性。最后,提及了线上诊断工具 Arthas 和性能调优工具 JProfiler,分别用于生产环境排障和性能优化。 适合人群:所有希望提高开发效率的程序员,尤其是有一定开发经验的软件工程师和技术团队。 使用场景及目标:①选择合适的 IDE 提升编码速度和代码质量;②利用 AI 编程助手加快开发进程;③通过 Git 实现高效的版本控制和团队协作;④使用 Postman 管理 API 的全生命周期;⑤借助 SonarQube 提高代码质量;⑥采用 Docker 实现环境一致性;⑦运用 Arthas 和 JProfiler 进行线上诊断和性能调优。 阅读建议:根据个人或团队的需求选择适合的工具,深入理解每种工具的功能特点,并在实际开发中不断实践和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值