首页 > 其他分享 >数论--有关模运算的巧妙

数论--有关模运算的巧妙

时间:2024-06-21 11:59:51浏览次数:25  
标签:10 运算 -- LL mid 数论 int sum 好数

萌萌的好数

链接:https://ac.nowcoder.com/acm/contest/84851/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

萌萌喜欢“好数”,这种“好数“需要满足以下两个条件:
1.该数对 3 取模不为 0
2.该数的最后一位数字不为 3
请你告诉他第 n 个好数是什么。

输入描述:

第一行读入一个正整数 t,表示有 t 组数据。
接下来 t 行,每行一个正整数 n。
1 ≤ t ≤ 100
1 ≤ n ≤ 1012

输出描述:

对于每个 n,输出一个正整数,为第 n 个好数

示例1

输入

3
1
4
9

输出

1
5
14

说明

前 9 个好数为 1,2,4,5,7,8,10,11,14。










方法一

  • 模 3 为 0 ,即每 3 个数一定为一个数,规律为 3
  • 最后一位为 3 ,即每 10 个数为一个周期
  • 这些要排除掉
  • 猜想规律为 30 一个周期,有规律出现,因为 3 和 10 的最小公倍数为 30,所以猜想 30 个数内可能有规律
  • 最后发现确实是,30 个数内都为 18 个好数
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 30;
LL a[N] = { 1, 2, 4, 5, 7, 8, 10, 11, 14, 16, 17, 19, 20, 22, 25, 26, 28, 29 };

int main()
{
    int t;
    cin >> t;

    while (t--)
    {
        LL n;
        cin >> n;
        cout << ((n - 1) / 18) * 30 + a[((n - 1) % 18)] << endl;
    }
    return 0;
}

方法二

  • 用容斥原理的思想思考,将不是好数的排除掉,也就是假设一个当前数字,是否能算出包括它的前面所有数字中好数的个数
  • 这样在进行二分找数字,即可求解
  • 不是好数的满足
    • 能被 3 整除的数,有 n / 3 个,
    • 个位上是数字 3 的数个数,n / 10 + (n % 10 >= 3)
    • 个位上数字是 3 并且又能被 3 整除,n / 3 / 10 + ((n / 3) % 10 >= 1),n / 3 是所有的能被 3 整除的数,在除以 10 就是个位是 3 的周期,最后的处理是除以 10 为 0 的情况的讨论
  • 这样计算后,将其第一个第二个加起来,减去第三个就是不是好数的个数,也就能统计出好数的个数
#include <iostream>
#include <vector>
using namespace std;
typedef long long LL;
LL n;

bool check(LL x)
{
    LL sum1 = x / 3;
    LL sum2 = x / 10 + (x % 10 >= 3);
    LL sum3 = (x/3) / 10 + ((x/3) % 10 >= 1);
    LL sum = x - (sum1 + sum2 - sum3);
    // 注意这里不能反正写判断,因为会找到比实际数大的情况出现,比如样例
    // 5 是答案,反着找到的 6 也满足,因为 6 不是好数,所以等同于 5 ,但是会找到 6 ,这就有问题,
    // 反着是指:if(sum <= n) return true; 然后二分边界也随之改变为l = mid,r = mid - 1
    if(n <= sum) return true;    
    else return false;
}

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
    
        LL l = 1, r = 1e14;
        while(l < r)
        {
            LL mid = l + r >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        cout << r << endl;
    }
    return 0;
}

或者

#include <iostream>
#include <vector>
using namespace std;
typedef long long LL;
LL n;

bool check(LL x)
{
    LL sum1 = x / 3;
    LL sum2 = x / 10 + (x % 10 >= 3);
    LL sum3 = (x/3) / 10 + ((x/3) % 10 >= 1);
    LL sum = x - (sum1 + sum2 - sum3);
    if(sum < n) return true;
    else return false;
}

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
    
        LL l = 1, r = 1e14;
        while(l < r)
        {
            LL mid = l + r >> 1;
            if(check(mid)) l = mid + 1;
            else r = mid;
        }
        cout << r << endl;
    }
    return 0;
}

方法三

  • 记忆化搜索方式----dp 方式
  • dp[i][j] 定义为第 i 位和为 j 的方案数
  • 从最高位开始 dfs 搜索,用 limit 作为限制,也就是后面的位的数字是否可以随便选择从 0~9 的任意数字
  • 如果 limit 为 0 ,表示没有限制,况且 dp 有值,那么直接返回即可,这里理解是都在没有限制的情况下,那么后面组成的情况都一致,就是加上当前位以前的 sum,满足好数的个数都一致,因为后面都没有限制,都是随便选择
  • 如果有限制,那么不返回,单独进行返回 ans,也就是计算的值
  • dp 记录的是这个位之后的数字加上当前位之前的 sum, 能构成的好数的集合
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
LL dp[20][200], num[20];
LL n;

// 位数 和 限制--最高位的取法
LL dfs(int weishu, int sum, int limit)
{
    if(weishu < 1)
    {
        if(sum % 3 == 0) return 0;
        else return 1;
    }
    
    if(!limit && dp[weishu][sum] != -1) return dp[weishu][sum];
    
    // 没有限制,就是 0~9,有限制就是当前位的最大数
    int maxnum = limit ? num[weishu] : 9;
    
    LL ans = 0;
    for(int i = 0; i <= maxnum; i++)
    {
        if(weishu == 1 && i == 3) continue;
        ans += dfs(weishu - 1, sum + i, (limit && i == maxnum));
    }
     // 这里不会重复更新,有数且满足 limit == 0,已经 return
    if(!limit) dp[weishu][sum] = ans;
     
     // 这里就是 limit == 1 的时候单独讨论,返回,怕影响 dp
    return ans;
}

bool check(LL x)
{
    memset(num, 0, sizeof num);
    memset(dp, -1, sizeof dp);
    
    int k = 0;
    while(x)
    {
        num[++k] = x % 10;
        x /= 10;
    }
    
    LL sum = dfs(k, 0, 1);
    if(sum < n) return true;
    else return false;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        
        LL l = 0, r = 1e14;
        while(l < r)
        {
            LL mid = l + r >> 1;
            if(check(mid)) l = mid + 1;
            else r = mid;
        }
        cout << l << endl;
    }
    return 0;
}

标签:10,运算,--,LL,mid,数论,int,sum,好数
From: https://www.cnblogs.com/xingzhuz/p/18257936

相关文章

  • 敏捷方法对于快速软件开发至关重要
    介绍敏捷方法是指在项目管理领域中,一种旨在提供高质量软件解决方案的协作和灵活方法。与传统的项目管理方法(瀑布式)相比,敏捷方法有很大不同,它更注重迭代进度、反馈整合、客户满意度和团队协作。历史与演变敏捷方法论的起源可以追溯到20世纪70年代和80年代,当时软件开......
  • 成为黑客第一步,从熟练掌握运维常见的工具开始
    文章目录前言一、开发工具二、自动化构建和测试三、持续集成&交付四、部署工具五、维护六、监控,警告&分析前言开源的工具是大家梦寐以求的。这里列举了多款最棒的开源工具,可以很好的实行DevOps一、开发工具版本控制&协作开发01版本控制系统GitGit是一个开源的分......
  • 怎么使用云桌面(云电脑)?ToDesk新手入门教程
    在当今数字化时代,个人用户对于电脑性能的需求日益提升,而云电脑(又可称为云桌面)作为一种新型的电脑配备模式,正在逐渐进入人们的视野。对于很多新手来说,可能是第一次接触到云电脑软件,今天小社长就以ToDesk云电脑为例子,为大家详细解析如何从零开始,轻松上手云电脑。【必备工具和设备......
  • 【TensorFlow深度学习】开源社区支持与GitHub上贡献代码的流程
    开源社区支持与GitHub上贡献代码的流程开源社区支持与GitHub上贡献代码的流程:携手共创软件未来1.开源社区支持的意义2.如何在GitHub上找到合适的项目3.贡献代码的流程3.1.Fork与Clone3.2.创建分支3.3.修改代码3.4.提交与推送3.5.创建PullRequest......
  • ToDesk云电脑性能如何?价格划算吗?
    云电脑是最近兴起的一种新型计算机形态。当用户面临电脑配置太低,无法顺畅打开大型软件,满足不了日常玩游戏或者高性能渲染,这时候你只需要租借一个高配置的云电脑。不需要额外购入任何设备,在原来的电脑上下载云电脑的软件,通过网络连接就能在云端上使用云电脑,轻轻松松带动各种3D游戏......
  • 制作耳机壳的UV树脂和塑料材质相比优势有哪些?
    制作耳机壳的UV树脂和塑料材质相比优势有哪些?制作耳机壳的UV树脂相比塑料材质有以下优势:高强度与耐磨性:UV树脂具有高强度和耐磨性,能够更好地保护耳机内部零件,延长耳机使用寿命。相比之下,塑料材质可能较易磨损或刮伤。耐高温:UV树脂具有较好的耐高温性能,即使在炎热的环境中也......
  • 【TensorFlow深度学习】量化压缩技术在降低模型体积中的应用
    量化压缩技术在降低模型体积中的应用量化压缩技术在降低模型体积中的应用1.引言2.量化压缩基础3.实战:使用TensorFlowLite进行模型量化4.评估量化效果5.结果分析与优化建议6.结语量化压缩技术在降低模型体积中的应用在深度学习领域,模型的......
  • 从理论到实践掌握UML
    统一建模语言(UML)是软件工程师用来设计软件系统的一种工具,就像是一套图形化的说明书。它让开发团队能够以图形化的方式来理解、设计和开发软件系统,比起用文字来描述,更加直观易懂。本文通过UML实例化的理论和实践相合,以电商系统为例,演示如何将UML实例化应用于实际项目中。无论......
  • 基于Python爬虫的城市天气数据可视化分析
    基于Python爬虫的城市天气数据可视化分析一、项目简介二、项目背景三、Python语言简介四、网络爬虫简介五、数据可视化简介六、天气数据爬取与存储6.1获取目标网页6.2发送请求6.3提取数据6.4保存数据七、天气数据可视化7.1天气现象轮播图7.2历......
  • 幼儿园报名(抢注)js脚本
    测试页面:https://www.wjx.cn/vm/YsVYnK1.aspxdocument.querySelector("#q1").value="姓名";//性别;//constsex1={男:"#q2_1",女:"#q2_2"};//document.querySelector(sex1.男).click();document.querySelector("#q2_1").cl......