首页 > 编程语言 >【每日一题】【DFS】【试除法求约数】【大剪枝】清楚姐姐跳格子 牛客周赛 Round 54 D题 C++

【每日一题】【DFS】【试除法求约数】【大剪枝】清楚姐姐跳格子 牛客周赛 Round 54 D题 C++

时间:2024-08-05 11:52:28浏览次数:17  
标签:约数 剪枝 visi k2 int vis k1 周赛 include

牛客周赛 Round 54 D题

清楚姐姐跳格子

题目背景

牛客周赛 Round 54

题目描述

在这里插入图片描述

样例 #1

样例输入 #1

5
2 3 1 5 4

样例输出 #1

2

在这里插入图片描述

做题思路

首先知道 a i ≥ 1 a_i \ge 1 ai​≥1,所以必定有一个正整数因子1
至少可以从第一格一步步的到达第 n n n格,所以答案肯定是有的。

假定 v i s i vis_i visi​为从第 i i i格到第 n n n格的最少步数。
那么初始化为

for(int i=1;i<=n;i++)cin >> a[i] , vis[i] = n-i;

后面考虑假如一直往右跳的可能。

这时候从前往后遍历的话会导致前面用了后面的 v i s vis vis但该 v i s vis vis并不是真正的从第 i i i格到第 n n n格的最少步数。

所以考虑从后往前遍历,这样遍历到前面用后面的 v i s vis vis就是一直往右跳真正的从第 i i i格到第 n n n格的最少步数。

这时就产生了第一个“状态转移“方程vis[i] = min(vis[i],vis[i+k]+1)
其中 k k k为 a i a_i ai​的一个正整数因子。

现在再考虑又往右又往左的情况。
实际上就是假如该点的 v i s i vis_i visi​变了,那么依附于其(或者“状态转移“方程出现 v i s i vis_i visi​)的 v i s j vis_j visj​全都得变。

简单来说就是当第 i i i个格子的 v i s i vis_i visi​(为从第 i i i格到第 n n n格的最少步数)变少了,那么如果存在一个 j j j并且第 j j j个格子能跳到第 i i i个格子那么该格子的 v i s j vis_j visj​就可能变少。

如果 v i s j vis_j visj​变少,只可能变成 v i s i + 1 vis_i + 1 visi​+1,因为现在是 v i s i vis_i visi​变少了,更新完 v i s i vis_i visi​后需要检查 v i s j vis_j visj​需不需要更新

其状态转移方程为 v i s j = min ⁡ ( v i s i + 1 , v i s j ) vis_j = \min{(vis_i+1,vis_j)} visj​=min(visi​+1,visj​)

同理如果 v i s j vis_j visj​变少也需要重复以上操作。

总结:
本题核心为vis[i] = min(vis[i],vis[i+k]+1)
因为该方程不满足无后效性,所以使用dfs进行关联更新

代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <tuple>
#include <cstring>
#include <cmath>
#define int long long
using namespace  std;
const int N = 1e5+10;
const int INF = 0x3f3f3f3f3f3f3f3f;
vector<vector<int>>connect(N,vector<int>());
int vis[N] , n , a[N];
void dfs(int x){
    for(auto j :connect[x]){
        if(vis[j] > vis[x]+1){
            vis[j] = vis[x] + 1;
            dfs(j);
        }
    }
}
signed main(){
    cin >> n;
    for(int i=1;i<=n;i++)cin >> a[i] , vis[i] = n-i;

    for(int i=n-1;i>=1;i--){
        int x = a[i] , u = i;
        for(int j=1;j<=x/j;j++){
            if(j > n)break;//注意重点剪枝,大于n必定跳出格子
            if(x%j == 0){
                int k1 = j , k2 = x/j;

                if(k1 + u <= n && k1 + u >= 1 && vis[k1+u] + 1 < vis[u]){
                    vis[u] = vis[k1 + u] + 1;
                    connect[u+k1].push_back(i);
                }

                if(u - k1 >= 1 && u - k1 <= n){
                    vis[u] = min(vis[u],vis[u - k1] + 1);
                    connect[u-k1].push_back(i);
                }

                if(k2 + u <= n && k2 + u >= 1 && vis[k2+u] + 1 < vis[u]){
                    vis[u] = vis[k2 + u] + 1;
                    connect[k2+u].push_back(i);
                }

                if(u - k2 >= 1 && u - k2 <= n){
                    vis[u] = min(vis[u - k2] + 1,vis[u]);
                    connect[u-k2].push_back(i);
                }

            }
        }
        dfs(i);
        //for(int i=1;i<=n;i++)cout << vis[i] << " \n"[i==n];
    }

    cout << vis[1];
    return 0;
}

标签:约数,剪枝,visi,k2,int,vis,k1,周赛,include
From: https://blog.csdn.net/weixin_72899100/article/details/140923253

相关文章

  • yolov8的模型剪枝教程
            模型剪枝是用在模型的一种优化技术,旨在减少神经网络中不必要的参数,从而降低模型的复杂性和计算负载,进一步提高模型的效率。    模型剪枝的流程:约束训练(constainedtraining)、剪枝(prune)、回调训练(finetune)    本篇主要记录自己YOLOv8模型剪枝......
  • pytorch中中的模型剪枝方法
     一,剪枝分类 所谓模型剪枝,其实是一种从神经网络中移除"不必要"权重或偏差(weigths/bias)的模型压缩技术。关于什么参数才是“不必要的”,这是一个目前依然在研究的领域。 1.1,非结构化剪枝 非结构化剪枝(UnstructuredPuning)是指修剪参数的单个元素,比如全连接层中的单个权......
  • LeetCode 136场双周赛 Q4. 标记所有节点需要的时间
    这道题也是一道比较经典的树形dp模板题;太久没写了,赛时一眼就想到了,但是敲的时候摸索了半天,还是没敲出来;首先看题目,需要求出无向树上从每个节点为树根节点到其他所有节点中最长路径的值,然后每条边的距离其实就是,如果目的地是奇数距离为1,目的地是偶数距离为2那么这个逻辑很简单,其......
  • Leetcode 第 135 场双周赛题解
    Leetcode第135场双周赛题解Leetcode第135场双周赛题解题目1:3222.求出硬币游戏的赢家思路代码复杂度分析题目2:3223.操作后字符串的最短长度思路代码复杂度分析题目3:3224.使差值相等的最少数组改动次数思路代码复杂度分析题目4:思路代码复杂度分析Leetcode......
  • “葡萄城杯”牛客周赛 Round 53
    A 小红小紫投硬币print(1/2)B 小红的字符串s=input()#直接接受输入n=len(s)#计算字符串长度#初始化变量result,用于累加每一步的最小移动次数result=0#遍历字符串的前半部分foriinrange(n//2):#计算当前字符与其对称字符的ASCII码差值......
  • LeetCode 408场周赛,Q3. 统计 1 显著的字符串的数量;问题分析
    https://leetcode.cn/contest/weekly-contest-408/problems/count-the-number-of-substrings-with-dominant-ones/description/、、这题难度是middle,但是确实有点强思维的味道,赛时思考了许久,没想到好方向,最后想了个线段树的解法。。当然最后超时了861/884,二十多个用例过不去;......
  • 基础数论 质数与约数
    基础数论前置芝士:等比数列求和:\(S_n=a_0\frac{1-q^n}{1-q}\)质数与约数:整除与约数设\(n\)为非负整数,\(d\)为正整数,若\(\frac{n}{d}\)为整数,则称\(d\)整除\(n\),记为\(d\midn\)。此时,则称\(d\)是\(n\)的约数,或因数、因子;称\(n\)为\(d\)的倍数。质数......
  • leetcode周赛407
    A.使两个整数相等的位更改次数ac代码:classSolution{public:intminChanges(intn,intk){inta[40]={0},b[40]={0};for(inti=0;i<32;i++)a[i]=n>>i&1;for(inti=0;i<32;i++)b[i]=k>>i&1;i......
  • AcWing871. 约数之和
    题目链接:https://www.acwing.com/problem/content/description/873/题目叙述:给定n个正整数ai,请你输出这些数的乘积的约数之和,答案对10^9+7取模。输入格式第一行包含整数n。接下来n行,每行包含一个整数ai。输出格式输出一个整数,表示所给正整数的乘积的约数之和,答案需对......
  • AcWing 870. 约数个数
    题目叙述:题目链接:https://www.acwing.com/video/295/给定n个正整数ai,请你输出这些数的乘积的约数个数,答案对1e9+7取模。输入格式第一行包含整数n。接下来n行,每行包含一个整数ai。输出格式输出一个整数,表示所给正整数的乘积的约数个数,答案需对1e9+7取模。数据范......