首页 > 其他分享 >2005NOIP普及组真题 4. 循环

2005NOIP普及组真题 4. 循环

时间:2024-06-03 12:30:44浏览次数:23  
标签:1234 10 组真题 int 普及 循环 Multiply 2005NOIP 进位

线上OJ:

【05NOIP普及组】循环

核心思想:高精度
1、本题用到了标准的高精度乘法模板

void init(int a[]) //传入一个数组
{
    string s; 
    cin >> s;  //读入字符串s 
    a[0] = s.length();   //用a[0]计算字符串s的位数 
    for(i = 1; i <= a[0]; i++)  a[i] = s[a[0]-i] - '0';   //将数串s转换为数组a,并倒序存储 
}
for (i = 1; i <= lena; i++)
{
    x = 0;                                     //用于存放进位
    for (j = 1; j <= lenb; j++)                //对乘数的每一位进行处理
    {
        c[i+j-1] = a[i] * b[j] + x + c[i+j-1]; //当前乘积+上次乘积进位+原数
        x = c[i+j-1] / 10;
        c[i+j-1] %= 10;
    }
    c[i+lenb] = x;                           //进位
}
lenc = lena + lenb;
while (c[lenc] == 0 && lenc > 1)  lenc--;    //删除前导0

2、本题要求的是末 k 位的循环节长度。需要从最低位开始判断
假设一个数的末尾四位数字为 1234,要求 1234 的循环节。
1、先判断最后一位 4 的循环节,假设找到是x,即 ( 1234 ) x (1234)^x (1234)x 的个位保持 4 不变。
2、再找倒数第二位 3 的循环节。为了保证每次循环最后一位都保持 4 不变,故每一轮要以 ( 1234 ) x (1234)^x (1234)x 为基准进行累乘。假设找到是 y,则说明 ( ( 1234 ) x ) y ((1234)^x)^y ((1234)x)y的末两位保持 34 不变。
3、再找倒数第三位 2 的循环节。为了保证每次循环末两位保持 34 不变,故每一轮要以 ( ( 1234 ) x ) y ((1234)^x)^y ((1234)x)y 为基准进行累乘。假设找到是 z,则说明 ( ( ( 1234 ) x ) y ) z (((1234)^x)^y)^z (((1234)x)y)z 的末三位保持 234 不变。
4、再找倒数第四位 1 的循环节。为了保证每次循环末三位保持 234 不变,故每一轮要以 ( ( ( 1234 ) x ) y ) z (((1234)^x)^y)^z (((1234)x)y)z 为基准进行累乘。假设找到是 r,则说明 ( ( ( ( 1234 ) x ) y ) z ) r ((((1234)^x)^y)^z)^r ((((1234)x)y)z)r 的末四位保持 1234 不变。
故 1234 的循环节为 x ∗ y ∗ z ∗ r x*y*z*r x∗y∗z∗r
3、我们将上述的 ( 1234 ) x (1234)^x (1234)x , ( ( 1234 ) x ) y ((1234)^x)^y ((1234)x)y , ( ( ( 1234 ) x ) y ) z (((1234)^x)^y)^z (((1234)x)y)z 称为每一轮的累乘单位
下表描述了基本判断过程:

在这里插入图片描述

题解代码:
#include <bits/stdc++.h>
using namespace std;

const int N = 1005;  // 10^100的数字长度有1000位

int k; //结果取末k位

void Multiply(int a[], int b[], int r[]) //a * b = r 高精乘高精 结果只取末k位
{
    for(int i = 1; i <= a[0]; ++i)
    {
        int x = 0;  // 存放进位
        for(int j = 1; j <= b[0]; ++j)  // 对乘数的每一位进行处理
        {
            r[i+j-1] = a[i]*b[j] + x + r[i+j-1]; // 当前乘积 + 上次乘积进位 + 原数
            x = r[i+j-1] / 10;  // 如果r[i+j-1]超过10,则产生进位
            r[i+j-1] %= 10;     // 仅保留个位
        }
        r[i+b[0]] += x; // 存储最后一次产生的进位
    }

    int len = a[0] + b[0];   // 初始化计算结果的位数(举例,3位数*1位数的结果最多是4位数)
    while(r[len] == 0 && len > 1)  len--;  // 去除前导0

    r[0] = min(len, k);  // 存储计算结果的长度至 r[0]。如果计算结果超过了k位,只取k位
}

// c = c*a ,用于计算累乘乘积。
// 为高精乘高精。在调用Multiply(c, a, r)时返回的结果只取末k位
void Multiply(int c[], int a[])
{
    int r[N] = {};
    Multiply(c, a, r);  // r = a*c
    memcpy(c, r, sizeof(r)); // r复制回c,结果只考虑 r[0]位
}

// a = a*b,用于计算幂次方的乘积。举例 (n^100)^5=n^500
// 高精乘低精
void Multiply(int l[], int j)
{
    int x = 0, i;
    for(i = 1; i <= l[0]; ++i) // 对每一位进行处理(倒序存储,l[1]为个位)
    {
        l[i] = l[i] * j + x; // 每一位相乘,+低位的进位
        x = l[i] / 10;  // 如果l[i]超过10,则产生进位
        l[i] %= 10;     // 仅保留个位
    }
    while(x > 0) // 存储最后一次产生的进位
    {
        l[i] = x % 10;
        x /= 10;
        i++;
    }
    while(l[i] == 0 && i > 1)   i--;  // 去除前导0
    l[0] = i;   // 保存计算结果的长度至 l[0]
}

int main()
{
    int n[N] = {}, a[N] = {}, b[N] = {}, c[N] = {}, l[N] = {1,1}; // n:存储原数;a:累乘单位n^t; b:存储n×n^t,n×n^2t ; c:存储每一轮的累乘结果,如 n^2t;l:循环长度 初值为1
    string s;
    cin >> s >> k;  // 读入字符串s和末尾k

    n[0] = s.length(); // 用n[0]存储数字的长度
    for(int i = 1; i <= n[0]; i++)  n[i] = s[ n[0] - i ] - '0'; // 将数串s转换为数组a,并倒序存储

    memcpy(a, n, sizeof(n)); // 初始化累乘单位
    for(int i = 1; i <= k; ++i) // 从个位开始,逐次计算每一位对应的循环周期。由于 n 是倒序存储,所以n[1]是个位,n[2]是十位,n[3]是百位...
    {
        bool isFound = false;   // 第i位的循环长度是否找到

        c[0] = c[1] = 1; // 存储累乘乘积,初始化为1,c[0]存储c的位数。举例,累乘单位n^t,则c分别为1,n^t,(n^t)^2,(n^t)^3...
        for(int j = 1; j <= 10; ++j)  // 如果累乘单位n^t经过10轮还没有出现重复,则说明不会重复了(因为0-9只有十个数字)。
        {
            Multiply(c, a); // 高精乘高精,计算累乘乘积
            memset(b, 0, sizeof(b));
            Multiply(c, n, b);//高精乘高精 b = c * n
            if(b[i] == n[i])  //如果倒数第i位又变回为原来的倒数第i位
            {
                Multiply(l, j);//高精乘低精 找到第i位的循环长度为j
                isFound = true;
                break;
            }
        }
        if(isFound == false)
        {//如果没找到,则不存在循环长度
            cout << -1;
            return 0;
        }
        memcpy(a, c, sizeof(c));
    }
    for(int i = l[0]; i >= 1; i--)  cout << l[i]; // 逆序输出循环长度
        
    return 0;
}

标签:1234,10,组真题,int,普及,循环,Multiply,2005NOIP,进位
From: https://blog.csdn.net/weixin_40252159/article/details/139401794

相关文章

  • 【普及二】【九 动态规划二】【第6题】
    思考过程:1.有题目联想到DP基础——>最大子段和2.分析题目,可知此题本质为修改后的最大子段和3.根据题目要求,修改状态将f[i]——>i结尾最大子段和改为f[i][j]——>i结尾,加j个最大子段和4.设计方程(有最大子段和原题更改)收获要学会从新题目中发现旧题目,更改后即......
  • 打卡信奥刷题(36)用Scratch图形化工具信奥P1705 [ 普及组] 爱与愁过火
    爱与愁过火题目背景(本道题目隐藏了两首歌名,找找看哪~~~)《爱与愁的故事第一弹·heartache》第三章。爱与愁大神说这是ta的伤心指数,只不过现在好很多了,翻译只是看你无聊让你动动脑筋罢了(shit~~~)。虽然月落乌啼嘴上骂着:“我去年买了个表……纽曼表……”,但是结果还是请爱与......
  • CSP历年复赛题-P1981 [NOIP2013 普及组] 表达式求值
    原题链接:https://www.luogu.com.cn/problem/P1981题意解读:中缀表达式求值,只有+,*,没有括号,保留后4位。解题思路:中缀表达式求值的典型应用,采用两个栈:符号栈、数字栈,对于没有括号的情况,只需要如下步骤:1、遍历表达式每一个字符2、如果遇到数字,则持续提取数字,保存整数到数字栈3、......
  • 【NOIP2018普及组复赛】题1:标题统计
    题1:标题统计题目描述凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符?注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。【输入格式】输入文件只有一行,一个字符串......
  • 儿童节,GDKOI2024普及组
    儿童节快乐捏捉迷藏Zayin和Ziyin在一棵\(n\)个节点的树上,Zayin从\(a\)节点开始,每次可以走\(da\)步,Ziyin从\(b\)节点开始,每次可以走\(db\)步,走到了另一个人所在的节点的人获胜。求在最优策略下,两者谁会获胜。题解:令\(a\)和\(b\)之间的距离是\(dis\)简单易得当\(dis<da\)时,Zay......
  • 打卡信奥刷题(35)用Scratch图形化工具信奥P1664 [ 普及组] 每日打卡心情好
    每日打卡心情好题目背景在洛谷中,打卡不只是一个简单的鼠标点击动作,通过每天在洛谷打卡,可以清晰地记录下自己在洛谷学习的足迹。通过每天打卡,来不断地暗示自己:我又在洛谷学习了一天,进而帮助自己培养恒心、耐心、细心。此外,通过打卡,还可以获取经验值奖励,经验值的多少在一定......
  • 低代码与大模型时代:技术的进化与人工智能的普及
    在当前快速发展的技术环境中,低代码和大模型成为了推动技术创新和人工智能普及的关键因素。低代码开发平台使得软件开发变得更简单和高效,大模型则提供了更强大的智能能力。这篇文章将探讨低代码和大模型在技术领域的应用,以及它们对于普通用户和开发者的影响。低代码开发平台的......
  • CSP历年复赛题-P1980 [NOIP2013 普及组] 计数问题
    原题链接:https://www.luogu.com.cn/record/160821231题意解读:统计1~n中x的个数。解题思路:枚举每个数,提取每一位,判断是否等于x。100分代码:#include<bits/stdc++.h>usingnamespacestd;intn,x,ans;intmain(){cin>>n>>x;for(inti=1;i<=n;i++)......
  • CSP历年复赛题-P1078 [NOIP2012 普及组] 文化之旅
    原题链接:https://www.luogu.com.cn/problem/P1078题意解读:1~n个国家,每个国家有自己的文化,不同国家文化可以相同,要从起点遍历到终点,已经学习过的文化不能重复学习,已经学习过的文化被某个文化歧视的国家也不能遍历,且不同国家之间有边,边有不同的距离,计算从起点到终点的最短路径。解......
  • 打卡信奥刷题(32)用Scratch图形化工具信奥P1055 [NOIP2008 普及组] ISBN 号码
    [NOIP2008普及组]ISBN号码题目描述每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括999位数字、1......