3.28 做做看6 题解

问题 A: 一无所有

时间限制: 1 Sec 内存限制: 128 MB
题目描述
kk穷的只剩下钱,但是她却很不喜欢这种感觉,这都只是数字,所以她希望让自己一无所有,把数字变为0

她现在有一种花钱方式:

每一步有两种选择:1. 让数字减一   
			   2.将数字整除k 当数字能够整除k时

她需要你帮她计算需要多少步,才能变为0

输入
有t组输入样例,每组输入样例包括 数字 n 和 k ( 2 <= n <= 10^18, 2 <= k <= 10 ^ 18)
输出
对于每组输入样例,输出其变为0 所需步数
样例输入
3
99 4
59 7
77 6
样例输出
9
7
9

思路:将题目转化下,就可以知道大概思路,我们都知道,当除以任何大于1的正整数,数据减小的速度都会大于直接减1的速度,那么也就转化成了一个简单的贪心问题,如果能够整除k,就将n去除以k,不能的话,减到能够整除的k的数字,然而一次次减完再去判断会耗费很多时间,此处我们可以考虑采用求模的方式,模数放在我们小学的时候其实就是余数,多余的数字,整数倍的多余数字,也就是说,将n减去这个多余的数字,就是距离n最近的一个k的整数倍,n = m * k + a, 则 n - a = m * k. 那么这个a就是我们所需要减去的数字,即减去a次的1,操作数+a,然后整除k,操作数+1
当然,记住不要输出多余的东西,比如什么“请输入数字n:”、“数据不规范请重新输入” 这是交互端需要做的事,运算中不需要
代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
int main()
{
    ll n, k;
    int T;
 
    scanf("%d", &T);
    ll ans;
    while (T--) {
        ans = 0;
        scanf("%lld %lld", &n, &k);
        while (n) {
            if (n % k == 0) {
                while (n % k == 0) {
                    n /= k;
                    ans++;
                }
            }else {
                ans += (n % k);
                n -= (n % k);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

问题 B: 塑性

时间限制: 1 Sec 内存限制: 128 MB
题目描述
现在来玩一个游戏,当有x,y且x > y 存在 x 减去素数p(p可任意选择)任意次后 有x == y 则证明其有塑性

如果有塑性则输出YES 否则输出NO

注意 1 不是素数

输入
有 T 行数据 ( 1 <= T<= 100)

每行输入 x 和 y ( 0 < y < x <= 10 ^ 18)

输出
如果符合条件,输出YES, 否则输出NO
样例输入
2
42 32
41 40
样例输出
YES
NO

思路:转化下题目意思,即(x - y)是否是一个素数的整数倍,根据素数的性质,素数是只有被1和本身整除的整数,那么素数肯定是自身的整数倍,然后合数的性质为可以被除了1和本身之外的数字整除,那么我们往下递归思考,任何合数都存在除了1和本身外的因子,若存在素因子,那么其是素数的整数倍,若存在合因子,合因子再次拆分,将会拆分到只有素因子的情况,那么合因子也是素因子的整数倍,所以合数一定是一个素数的整数倍,当然欧拉筛法的原理也证明的这点,所以说,任意大于1的数字都是某个素数的整数倍。1不是素数,而它也只是1的整数倍,所以不存在塑性(我编的性质,别当真)
然后说下常见的判断素数法,不适用这题,不管是暴力还是优化的判断法,或者说是筛法,会出现超时或者超内存的情况,当数据在10^18时,判断一个素数在优化方法下会在1s以上,而筛法在打超过八位数的表的时候会将内存和时间都超了,所以也不太适用。
代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctype.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <stack>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <list>
typedef long long LL;
using namespace std;
#define mem(a) memset(a, 0, sizeof a)
int main()
{
    int T;
  
    cin >> T;
    while (T--) {
        LL a, b;
        cin >> a >> b;
        LL sub = a - b;
        if (sub == 1) {
            cout << "NO" << endl;
        }else cout << "YES" << endl;
    }
    return 0;
}

问题 C: 努力向上的计算姬

时间限制: 1 Sec 内存限制: 128 MB
题目描述
计算姬是一个的努力向上的好孩子,她在学习的课余时间,想试一试循环的计算,但是刚刚学会操作的她发现自己对底层运算的了解变得很浅。

所以她找来了你,希望你能编写一个程序,来模拟循环计算的结果。

但是夜深了,计算姬表示很困,所以她不想算太大的数字,于是她决定超过一千万的数字她就罢工(包括一千万)!!!

当她罢工的时候会输出"Go Out!!!".

现在需要你去编写一个程序,有三条命令:

  1. for循环的开头 f ,后带一个数字n,表示循环次数(0 < n <= 100)

2.for循环终止语句e,表示循环终止,每一个f 对应一个 n

  1. 自增指令,+,遇到使其加1

初始 x 为0

输入
第一行一个数字n, ( 0 < n <= 100)

第二行到第n + 1 行,每一行一个指令

输出
输出最终x的结果,如果x >= 10000000 输出"Go Out!!!"
样例输入
9
+
f 43
e
f 10
f 15
+
e
+
e
样例输出
161
提示
可能会造成 int 上溢
思路:
这题就是一道很普通的模拟题,用栈记录下之前每层循环的次数,遇到+时将循环次数总和加到答案中,如果当前总和超过10000000,那么退出运算

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
using namespace std;
typedef long long ll;
string a[120000];
int num[120000];
stack<ll> s;
int main()
{
    map <string, int> mp;
 
    mp["+"] = 0;
    mp["f"] = 1;
    mp["e"] = 2;
    int n;
    ll k = 1LL * 10000000;
    scanf("%d", &n);
    memset(num, 0, sizeof num);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
        if (mp[a[i]] == 1) cin >> num[i];
        // cout << a[i] << " " << num[i] << endl;
    }
    ll x = 0;
    ll tem = 1;
    // bool flag = false;
    bool flag_x = false;
    // cout << n << endl;
    for (int i = 0; i < n; ++i) {
        if (mp[a[i]] == 0 ) {
            if (s.empty()) x += 1;
            else x += s.top();
        }
        // cout << n << endl;
        if (mp[a[i]] == 1) {
            if (s.empty()) tem = 1;
            else tem = s.top();
            tem *= num[i];
            if (tem > k) s.push(k + 1);
            else s.push(tem);
        }
        // cout << n << endl;
        if (mp[a[i]] == 2) {
            s.pop();
        }
        if (x > k) {
            flag_x = true;
            break;
        }
        // printf("%I64d %I64d %d\n", x, tem, top);
    }
    // std::cout << "1" << '\n';
    if (flag_x) printf("Go Out!!!\n");
    else printf("%lld\n", 1LL * x);
    return 0;
}

三道题都来自 codeforce 的div2 AB ,前两题考察思维(A),最后一道属于数据结构范畴

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值