第14章动态规划

动态规划

  • 确定递推状态: f(n)+解释
  • 确定递推公式
  • 程序实现

优化:

  • 去除冗余状态
  • 状态重定义
  • 优化转移过程
  • 斜率优化

优化-递归+记忆化

if arr[n] return arr[n]

递归+记忆化(正向求解-递归) 或 改变求解顺序(逆向递归求解-循环) : 解决效率问题

用long long ,或者更大的:解决数值溢出,不够大问题

HZOJ 38 兔子繁殖问题

  1. 确定递推状态: f(n)为第n个月的时候兔子的数量
  2. 确定递推公式: f(1)=1 | f(2)=2 | f(n)=f(n-1)+f(n-2)
  3. 程序实现
#include <iostream>
using namespace std;
#define MAX_N 100
int digui_jiyihua_arr[MAX_N+5]={0};

int f(int n){
    if(n<=2) return n;
    if(digui_jiyihua_arr[n])return digui_jiyihua_arr[n]; //优化-增加记忆点,解决超时问题
    digui_jiyihua_arr[n]=f(n-1)+f(n-2);
    return digui_jiyihua_arr[n];
}
void acm_1_14_digui_jiyihua_test(){
    int n;
    cin>>n;
    cout << f(n) <<endl;
}

改变求解顺序

从低到高

long long acm_1_14_digui_jiyihua_f[105]={0};
void acm_1_14_digui_jiyihua_test2(){
    int n;
    cin>>n;
    acm_1_14_digui_jiyihua_f[1]=1;
    acm_1_14_digui_jiyihua_f[2]=2;
    for(int i=3;i<=n;i++){
        acm_1_14_digui_jiyihua_f[i]=acm_1_14_digui_jiyihua_f[i-1]+acm_1_14_digui_jiyihua_f[i-2];
    }
    cout << acm_1_14_digui_jiyihua_f[n] <<endl;
}
//
// Created by cry on 2024/3/24.
//
#include <vector>
#include <iostream>
using namespace std;
#define MAX_N 100
long long digui_jiyihua_arr[MAX_N+5]={0};

long long f(int n){
    if(n<=2) return n;
    if(digui_jiyihua_arr[n])return digui_jiyihua_arr[n]; //优化-增加记忆点,解决超时问题
    digui_jiyihua_arr[n]=f(n-1)+f(n-2);
    return digui_jiyihua_arr[n];
}
void acm_1_14_digui_jiyihua_test(){
    int n;
    cin>>n;
    cout << f(n) <<endl;
}
//大整数
class BigInt:
public vector<int>{
        public:
        BigInt()
        {
            push_back(0);
        }
        BigInt(int x)
        {
            this->push_back(x);
            process_digit();//处理大整数进位问题
        }
        //重载+=运算
        BigInt &operator+=(const BigInt &a){
            for(int i=0;i<a.size();i++){
                if(i >= size()) //如果位数超出了
                {
                    push_back(a[i]);

                }else at(i)+=a[i];
            }
            process_digit();
            return *this;
        }
        //重载加法运算
        BigInt operator+(const BigInt &a){
            BigInt ret(*this);//拷贝一下当前
            ret+=a;
            return ret;
        }
        //重载左移运算符

        //进位
        void process_digit() {
            for (int i = 0; i < size(); i++) {
                if (at(i) < 10) continue; //当前位置的值小于10,不需要处理
                //当前位置的值大于10,就进位
                if (i == size() - 1) push_back(0); //增加一位
                at(i + 1) += at(i) / 10;
                at(i) %= 10;
            }
            return ;
        }
};
// 重写左移运算符
ostream &operator<<(ostream &out,const BigInt &a){
    for(int i=a.size()-1;i>=0;i--){
        out << a[i];
    }
    return out;
}
BigInt acm_1_14_digui_jiyihua_f[105]={0};
void acm_1_14_digui_jiyihua_test2(){
    int n;
    cin>>n;
    acm_1_14_digui_jiyihua_f[1]=1;
    acm_1_14_digui_jiyihua_f[2]=2;
    for(int i=3;i<=n;i++){
        acm_1_14_digui_jiyihua_f[i]=acm_1_14_digui_jiyihua_f[i-1]+acm_1_14_digui_jiyihua_f[i-2];
    }
    cout << acm_1_14_digui_jiyihua_f[n] <<endl;
}
int main() {
    acm_1_14_digui_jiyihua_test2();
    return 0;
}

python解法 只需要记忆化就行了,类型不会出问题

#第一代,缺点:效率低 且 数据类型不够大
# dp_1(65) 直接跑不完
def dp_1(n):
    if(n<=2):
        return n
    return dp_1(n-1)+dp_1(n-2)
# 解决:添加记忆化
MAX_N=100
arr=[0]*(MAX_N+5)
def dp_2(n):
    if(n<=2):
        return n
    if arr[n]:return arr[n]
    arr[n]=dp_2(n-1)+dp_2(n-2)
    return arr[n]
n=int(input())
print(dp_2(n))
# 改变求解顺序
def dp_3(n):
    arr=[0]*(MAX_N+5)
    if(n<=2):return n
    arr[1]=1
    arr[2]=2
    for i in range(3,n+1):
        arr[i]=arr[i-1]+arr[i-2]
    return arr[n]
print(dp_3(n))

容斥原理的基本思想

  1. 在计数的时候为了没有重复 没有遗漏
  2. 再不考虑重叠的情况,把包含于某内容的所有对象数目先计算出来,然后把计数时重复的计算的数目排斥出去

加多的减掉,减多了加回来

  1. 结果既无遗漏又无重复—容斥原理

钱币问题

  • 确定递推状态: f[i][j]表示用i种钱币,凑足j元钱的方法总数

1 2 5 f(2)(5) ,前两种钱币凑5块有1 2 2 1 1 1 2 1 1 1 1 1三种

  • 确定递推公式

拆分:分成两个不相交的子集

​ a. 没有使用第i种钱币

​ b. 使用了第i种钱币

f[i][j]=f[i-1][j]+f[i][j-w[i]]

w:1 2 5

f(3)(5)=f(3-1)(5)+f(3)(5-5)

​ =f(2)(5)+f(3)(0)

​ =f(1)(5)+f(2)(3)+f(3)(0)

​ =f(1)(5)+f(1)(3)+f(2)(1)+f(3)(0)

​ =f(1)(5)+f(1)(3)+f(1)(1)+f(2)(0)+f(3)(0)

​ =f(0)(5)+f(0)(3)+f(0)(1)+f(1)(0)+f(2)(0)+f(3)(0)

​ =0+0+0+0+1+1+1

​ =3

  • 程序实现
//
// Created by cry on 2024/3/27.
//
#include <iostream>

using namespace std;
#define MAX_N 10000
#define MAX_M 20
int w[MAX_N+5];
int f[MAX_M+5][MAX_N+5]; //前m种钱币拼凑n元钱
void acm_1_14_dp_money_test(){
    int m,n;
    cin >> m>> n;
    for(int i=1;i<=m;i++) { //钱币类型遍历
        cin >> w[i];
    }
    for(int i=1;i<=m;i++){
        f[i][0]=1; //前i种钱币凑0元钱为1种
                // 因为f(2)(5)+f(3)(0)=f(3)(5)
                // 3+1=4,所以f(3)(0)为1
        for (int j = 1; j <= n; j++) {
            f[i][j]=f[i-1][j];
            if(j<w[i])continue; //小于第i种钱币的面额
            f[i][j]+=f[i][j-w[i]];
            f[i][j] %= 9973;
        }
    }
    cout << f[m][n] << endl;
}

使用python实现

def get_dp_dp_money(m,n,w):
    # f=[[0]*(n+5)]*(m+5) //同一个地址
    f=[[0]*(n+5) for _ in range(m+5)] # 不同地址
    for i in range(1,m+1):
        f[i][0]=1 # 终止条件
        for j in range(1,n+1):
            f[i][j]=f[i-1][j]
            if(j<w[i-1]):continue #f(1)(3)没有值,为0
            f[i][j]+=f[i][j-w[i-1]]
            f[i][j]%=9973
    print(f[m][n])

if __name__=='__main__':
    m,n=list(map(int,input().split(" ")))
    w=list(map(int,input().split(" ")))
    w.append(0)
    get_dp_dp_money(m,n,w)

HZOJ40:爬楼梯

  • 确定递推状态: f[n]表示n级的方法总数

1 2 5 f(2)(5) ,前两种钱币凑5块有1 2 2 1 1 1 2 1 1 1 1 1三种

  • 确定递推公式

拆分:分成两个不相交的子集,且相加为全集

​ a. 最后一步跨两步:走到f[n-2]台阶的方法总数

​ b. 最后一步跨三步:走到f[n-3]台阶的方法总数

f[n]=f[n-2]+f[n-3]

  • 程序实现
#include <iostream>
using namespace std;
#define MAX_N 500
int res[MAX_N+5];
void acm_1_14_dp_palouti_test(){
    int n;
    res[0]=1;
    res[1]=0;
    res[2]=1;
    cin >> n;
    for(int i=3;i<=n;i++){
        res[i]=res[i-2]+res[i-3];
    }
    cout <<res[n]<<endl;
}

python

def palouti():
    n=int(input())
    res=[0]*505
    res[1]=0
    res[0]=1
    res[2]=1;
    for i in range(3,n+1):
        res[i]=res[i-2]+res[i-3]
    print(res[n])

palouti()

HZOJ 41:墙壁涂色

n块墙壁可以涂k种颜色

墙壁呈现环形,相邻两块墙壁不能相同

  • 确定递推状态:

    f[n][i][j]:n块墙壁,首墙壁i种颜色,尾墙壁j种颜色的方案数

  • 确定递推公式

拆分:分成两个不相交的子集,且相加为全集

​ a. 最后一步跨两步:走到f[n-2]台阶的方法总数

​ b. 最后一步跨三步:走到f[n-3]台阶的方法总数

f[n][i][j]=f[n-1][i][k] 且k!=j 最后累加: 首尾可能相同

f[n][i][j] 且 i!=j的项累加 :剔除首尾相同的

边界条件:f[1]={1,0,0, 0,1,0 0,0,1}

  • 程序实现
    解决内存超界的方法:使用滚动数组
//
// Created by cry on 2024/3/27.
//
#include <iostream>
using namespace std;
#define MAX_N 1000
#define MAX_K 10
int ys[2][MAX_K+5][MAX_K+5]; //使用滚动数组解决内存超限问题
void acm_1_14_dp_qiangBiTuSe_test(){
    int n,k;
    cin >> n>>k; //读取数据:n块墙壁涂k种颜色

    for(int i=1;i<=k;i++){
        ys[1][i][i]=1;
    } //初始化,f[1] ,对角线元素为1,其余为0
    for(int ws=2;ws<=n;ws++){
        for(int i=1;i<=k;i++){
            for(int j=1;j<=k;j++){
                ys[ws %2][i][j]=0;
                for(int l=1;l<=k;l++){
                    if(l==j){ continue;}
                    ys[ws%2][i][j]+=ys[(ws-1)%2][i][l];

                }
            }
        }
    }
    //提出i==j的部分
    int ans=0;
    for(int i=1;i<=k;i++){
        for(int j=1;j<=k;j++){
            if(i==j){ continue;}
            ans+=ys[n%2][i][j];
        }
    }
    cout << ans << endl;

}

python

#!/usr/bin/python3
# _*_ coding: utf-8 _*_
#
# Copyright (C) 2024 - 2024 Cry, Inc. All Rights Reserved
#
# @Time    : 2024/3/27 15:03
# @Author  : Cry
# @File    : 墙壁涂颜色.py
# @IDE     : PyCharm

MAX_N = 1000
MAX_K = 10
# f = [[[0] * (MAX_K + 5)] * (MAX_K + 5)] * 2 # f 是一个包含两个元素的列表。每个元素都是一个包含 (MAX_K + 5) * (MAX_K + 5) 个元素的二维列表。这意味着 f[0] 和 f[1] 是两个指向内存中相同位置的引用,因此,如果你修改 f[0],f[1] 也会受到影响
f = [[[0] * (MAX_K + 5) for _ in range(MAX_K + 5)] for _ in range(2)]
#f 是一个包含两个元素的列表。每个元素都是一个包含 (MAX_K + 5) * (MAX_K + 5) 个元素的二维列表。但是,与第一行代码不同的是,这里的两个二维列表是独立的,它们并不共享内存中的相同位置。因此,如果你修改 f[0],f[1] 不会受到影响。

def qiangbitumo():
    n, k = list(map(int, input().split(" ")))
    for i in range(1, k + 1):
        f[1][i][i] = 1  # 对角线元素为1
    for ws in range(2, n + 1):
        for i in range(1, k + 1):
            for j in range(1, k + 1):
                f[ws % 2][i][j] = 0
                for l in range(1, k + 1):
                    if l == j:
                        continue
                    f[ws % 2][i][j] += f[(ws - 1) % 2][i][l];
    ans = 0
    for i in range(1, k + 1):
        for j in range(1, k + 1):
            if i == j:
                continue
            ans += f[n % 2][i][j]
    print(ans)



qiangbitumo()

洛谷P1025 数的划分

  • 确定递推状态:

    f(i)(j):数字i分成j份的方法总数

  • 确定递推公式

拆分:分成两个不相交的子集,且相加为全集

​ a. 拆分的方案中有1的方案总数 :去掉1:剩下的总和为f(i-1)(j-1)

​ b. 拆分的方案中没有1的方案总数:每份都减去1,减j个1:f(i-j)(j)

递推公式:f[i][j]=f[i-1][j-1]+f[i-j][j]

边界条件:f[0][0]=1 f[i][1]=1

  • 程序实现

学习:在固定份数的前提统计:全集分成两个集合:

按照有1和没有1,有1减1,没有1每份都减去1

//
#include <iostream>
using namespace std;
#define MAX_N 200
#define MAX_K 6
int f1[MAX_N+5][MAX_K+5];
void acm_1_14_dp_shudehuafen_test(){
    int n,k;
    cin >> n >> k;
//    f(i)(j)=f(i-1)(j-1)+f(i-j)(j)
    f1[0][0]=1;  //将0拆成0份,方法为1
    for(int i=1;i<=n;i++){
//        设置边界条件
        f1[i][1]=1; //将i拆成1份,拆成方法总数为1
//        f[0][j] =0  f[i][1]=1
        for(int j=1,J=min(i,k);j<=J;j++){
            f1[i][j]=f1[i-1][j-1]+f1[i-j][j];
        }
    }

    cout << f1[n][k] <<endl;
}
int main(){
    acm_1_14_dp_shudehuafen_test();
    return 0;
}

python

# 定义最大值
MAX_N = 200
MAX_K = 6

# 初始化动态规划数组
f1 = [[0] * (MAX_K + 5) for _ in range(MAX_N + 5)]

def acm_1_14_dp_shudehuafen_test():
    # 输入 n 和 k
    n, k = map(int, input().split())
    
    # 初始化边界条件
    f1[0][0] = 1

    # 动态规划过程
    for i in range(1, n + 1): #求1到n的每个数的分成k份的份数
        f1[i][1] = 1 #分1份为1
        for j in range(1, min(i, k) + 1):
            f1[i][j] = f1[i - 1][j - 1] + f1[i - j][j]

    # 输出结果
    print(f1[n][k])

acm_1_14_dp_shudehuafen_test()

洛谷1028 数的计算

  • 确定递推状态:

    f(i):以i开头的合法数列数量

  • 确定递推公式

拆分:分成两个不相交的子集,且相加为全集

​ a. 不扩展:只有一个i 1个

​ b. 能扩展的,从i/2 i/2-1 i/2-2 … 1

递推公式:f[i]=1+Σf[j] (j<=i/2)

边界条件:f[1]=1 f[i][1]=1

  • 程序实现

学习:在固定份数的前提统计:全集分成两个集合:

按照有1和没有1,有1减1,没有1每份都减去1

#include <iostream>
using namespace std;
#define MAX_N 1000
int f2[MAX_N+5]={0};
void acm_1_14_dp_shudejisuan_test(){
    int n;
    cin >> n;
    //边界条件
    f2[0]=0;
    for(int i=1;i<=n;i++){
        f2[i]=1;
        for(int j=1;j<=i/2;j++){
            f2[i]+=f2[j]; //f[i]=1+Σ f[i/2]
        }
    }
    cout << f2[n] << endl;
}
int main(){
    acm_1_14_dp_shudejisuan_test();
    return 0;
}

python

def getNum():
    n=int(input())
    f=[0]*1005
    for i in range(1,n+1):
        f[i]=1
        for j in range(1,i//2+1):
            f[i]+=f[j]
    print(f[i])
getNum()

洛谷P1038 神经网络

使用拓扑序列计算神经元

Ci=Σ(WijCj) - Ui

拓扑序用于AOV网中,拓扑序是先行关系的 序列,前面的神经元是后面神经元的先行活动。

拓扑序生成原理:

  1. 将入度为0的点输出(无前驱的活动)
  2. 将 上一步输出的节点所在的弧都删除
  3. 重复第一第二步
  4. 若输出顶点数< 有向涂顶点数,则有回路,否则输出的即为拓扑序列
//
// Created by cry on 2024/3/28.
//
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
#define MAX_N 100
//Ci=Σ(w3ijCj) - Ui
int c[MAX_N+5];//状态值 Ci
int u[MAX_N+5];//被减去的 Ui
int w3[MAX_N+5][MAX_N+5 ]; //wij
vector<int> g[MAX_N+5];//每个节点指向的节点
int outdeg[MAX_N+5];//出度
int indeg[MAX_N+5];//出度
void acm_1_14_dp_shenjingwangluo_test(){
    //读取数据
    int n,p;
    cin >>n >>p;
    //读取每个节点的c值和u值
    for( int i=1;i<=n;i++){
        cin >> c[i] >> u[i];
        //如果是输入层节点,直接为-u[i]
        if (c[i]==0)c[i]=-u[i];
    }
    //读取若干条边的值
    for(int i=0,a,b,W3;i<p;i++){
        cin >> a >> b >>W3;
        w3[a][b]=W3; //w3[i][j]
        indeg[b]+=1;//入度+1
        outdeg[a]+=1; //出度+1
        g[a].push_back(b); //添加出边
    }
    queue<int> q;
    //将入度为0的点都加入到队列,将输入层节点都加进去(入度为0)
    for(int i=1;i<=n;i++){
        if(indeg[i])continue;
        q.push(i);
    }
    //开始按照拓扑序依次计算每个序列的值
    while(!q.empty()){
        int ind=q.front(); //计算当前节点状态值
        q.pop();
        if(c[ind]>0){ //当前节点被激活
            for(int i=0;i<g[ind].size();i++){
                int to=g[ind][i];
                c[to]+=w3[ind][to] * c[ind];
                //将index权值传播给下一个节点

            }
        }
        //将下一层节点所有入度-1
        for (int i=0;i<g[ind].size();i++) {
            int to=g[ind][i];
            indeg[to]-=1;
            if(indeg[to]==0){
                q.push(to); //入度为0,添加到输出
            }
        }
    }
    int flag=0;//如果输出层都<=0,就输出NULL
    for(int i=1;i<=n;i++){
        if(outdeg[i]) continue; //出度不为0 过
        if(c[i]<=0) continue; //未被激活 过
        cout << i<<" "<<c[i]<<endl;
        flag=1;
    }
    if(flag==0) cout <<"NULL" <<endl;

}

python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


MAX_N = 100

c = [0] * (MAX_N + 5)  
u = [0] * (MAX_N + 5)  
w3 = [[0] * (MAX_N + 5) for _ in range(MAX_N + 5)]  # wij
g = [[] for _ in range(MAX_N + 5)] 
outdeg = [0] * (MAX_N + 5)  
indeg = [0] * (MAX_N + 5)

def acm_1_14_dp_shenjingwangluo_test():
    
    n, p = map(int, input().split())
    for i in range(1, n + 1):
        c[i], u[i] = map(int, input().split())
        if c[i] == 0:
            c[i] = -u[i]
    for i in range(p):
        a, b, w = map(int, input().split())
        w3[a][b] = w  # w3[i][j]
        indeg[b] += 1  # 入度 +1
        outdeg[a] += 1  # 出度 +1
        g[a].append(b)  

    q = []
    for i in range(1, n + 1):
        if indeg[i]:
            continue
        q.append(i)
    while q:
        ind = q.pop(0)  
        if c[ind] > 0:  
            for i in range(len(g[ind])):
                to = g[ind][i]
                c[to] += w3[ind][to] * c[ind]

        for i in range(len(g[ind])):
            to = g[ind][i]
            indeg[to] -= 1
            if indeg[to] == 0:
                q.append(to)  

    flag = 0
    for i in range(1, n + 1):
        if outdeg[i]:
            continue
        if c[i] <= 0:
            continue
        print(f"{i} {c[i]}")
        flag = 1
    if not flag:
        print("NULL")

acm_1_14_dp_shenjingwangluo_test()

洛谷1044栈

1到n的栈的输出所有可能

  • 定义递归状态

    f[n]代表n个的合法方案数

  • 推导递推公式

分割:出战数字结尾为n到1的方案的数量,然后加起来,结果为f[n]总和

最后一个出栈数字为x的时候条件:

  1. 小于x的数字进行入栈出栈
  2. 所有小于x的数字在x入栈之前出完栈
  3. x一直在栈底,比x大的数字一直入栈出栈

当x作为结尾的方案总数为:f(x-1) * f(n-x) :小于x的方案数量乘上大于x的方案数量

  • 写代码
//
// Created by cry on 2024/3/28.
//
#include <iostream>
using namespace std;
#define MAX_N 18
int f_zhan[MAX_N+5];
void acm_1_14_dp_zhan_test(){
    int n;
    cin >> n;
    f_zhan[0]=1;
    for (int i=1;i<=n;i++) {
        f_zhan[i]=0;
        for(int x=1;x<=i;x++){
            f_zhan[i]+=f_zhan[x-1]*f_zhan[i-x];
        }
    }
    cout << f_zhan[n]<<endl;
}
int main(){
    acm_1_14_dp_zhan_test();
    return 0;
}

python

def zhan():
    n=int(input())
    f=[0]*20
    f[0]=1
    for i in range(1,n+1):
        f[i]=0
        for x in range(1,i+1):
            f[i]+=f[x-1]*f[i-x]
    print(f[n])
zhan()

洛谷1050 循环

打表:

输出y值

//
// Created by cry on 2024/3/28.
//
#include <iostream>
#include <string>
#include <vector>

using namespace std;
//大整数
class BigInt:public vector<int>{
public:
//    构造函数
    BigInt(){push_back(0);}
    BigInt(int n,int v):vector<int>(n,v){}
    BigInt(int x){
        push_back(x);
        process_digit();
        return;
}
    BigInt(string &s,int k) {
    for(int i=0,j=s.size()-1;i<k;i++,j--){
        push_back(s[j]-'0');
    }
    return ;
}
    BigInt operator*(const BigInt &a){
        BigInt ret(min(MaxLen,int(size()+a.size()-1)),0);
        for(int i=0;i<size();i++){
            for(int j=0;j<a.size();j++){
                if(i+j >=MaxLen)continue; //超过最大长度
                ret[i+j]+=at(i)*a[j];
            }
        }
        ret.process_digit();
        return ret;

}
    BigInt &operator *=(int x){
        for(int i=0;i<size();i++)at(i)*=x;
        process_digit();
        return *this;
}

static int MaxLen;

private:
    void process_digit(){ //进位
    for(int i=0;i<size();i++){
        if(at(i)<10)continue;
        if(i+1<MaxLen) {
            if (i + 1 == size()) push_back(0);
            at(i + 1) += at(i) / 10;
        }
        at(i) %= 10;
    }
    return ;
}
};

int BigInt::MaxLen=0;
ostream &operator<<(ostream &out,const BigInt &a){
    for(int i=a.size()-1;i>=0;--i){
        out << a[i];
    }
    return out;
}
int acm_1_14_dp_xunhuan_test(){
    string s;
    int k;
    cin >> s>>k;
    BigInt::MaxLen=k;
    BigInt n(s,k);
    BigInt pre_y=n,y;
    vector<int> arr;
    for(int i=0;i<n.size();i++){
        y=pre_y;
        int cnt=1;
        while((y*n).at(i)!=n[i]){
            y=y*pre_y;
            cnt+=1;
            if(cnt ==11)break; //当前位置不存在循环节
        }
        if(cnt ==11){
            cout <<"-1" <<endl;
            return 0;
        }
        arr.push_back(cnt);
        pre_y=y;
    }
    BigInt ans=1;
    for(int i=0;i<arr.size();i++){
        ans *= arr[i];
    }
    cout << ans << endl;
    return 0;
}
int main() {
    acm_1_14_dp_xunhuan_test();
    return 0;
}
//32 2
//4


 at(i) %= 10;
    }
    return ;
}
};

int BigInt::MaxLen=0;
ostream &operator<<(ostream &out,const BigInt &a){
    for(int i=a.size()-1;i>=0;--i){
        out << a[i];
    }
    return out;
}
int acm_1_14_dp_xunhuan_test(){
    string s;
    int k;
    cin >> s>>k;
    BigInt::MaxLen=k;
    BigInt n(s,k);
    BigInt pre_y=n,y;
    vector<int> arr;
    for(int i=0;i<n.size();i++){
        y=pre_y;
        int cnt=1;
        while((y*n).at(i)!=n[i]){
            y=y*pre_y;
            cnt+=1;
            if(cnt ==11)break; //当前位置不存在循环节
        }
        if(cnt ==11){
            cout <<"-1" <<endl;
            return 0;
        }
        arr.push_back(cnt);
        pre_y=y;
    }
    BigInt ans=1;
    for(int i=0;i<arr.size();i++){
        ans *= arr[i];
    }
    cout << ans << endl;
    return 0;
}
int main() {
    acm_1_14_dp_xunhuan_test();
    return 0;
}
//32 2
//4
  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厨 神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值