15级算法第一次上机解题报告

来源:互联网 发布:tempostorm 知乎 编辑:程序博客网 时间:2024/06/06 08:26

A 多项式计算器

解题思路:

求多项式的值,很典型的秦九韶算法的应用。如果使用朴素算法,每次算一个,枚举,对于每个i都要进行(i+1)次乘法,复杂度为O(),n在10000范围时显然会超时。可以对算的过程进行复用,记录下每次的,下一次的就由这个得到,复杂度降为O(n)。

更优的方法是秦九韶算法:

改写为:

记=,

取=

则即为多项式的值。

使用秦九韶算法求n次多项式值时,至多进行n次乘法和n次加法,十分高效。

此题中还要注意的是,运算过程中可能会超出int范围,全程long long并且及时取模即可。

代码:

#include <iostream>using namespace std;const int MaxT = 10000 + 7;const long long mod = (int) 1e6 + 7;int n, x, t, T = 0;long long ans;long long a[MaxT];int main() {    while (cin >> n >> x >> t) {        T++;        cout << "Case #" << T << ":\n";        while (t--) {            for (int i = 0; i <= n; i++) cin >> a[i];  //读入系数            ans = a[n] % mod;            for (int i = n - 1; i >= 0; i--) {  //秦九韶算法                ans *= x;                ans += a[i];                ans %= mod;            }            cout << ans << "\n";        }    }}


 

B 怠惰的园丁王木木

解题思路:

智力题。

由于题目描述中"每点体力可以将一根或者多根草减掉相同的任意高度",因此对于同一种高度的不同的草,都可以看作是同一根。所以,需要减少长度唯一的草的数量。

考虑先将后根草除去的长度,完成后它们的长度分别与前根草的长度相等。这个操作等于是花费1个代价将n根草变成了根草。不断重复这个过程,直到只剩一根草为止。

代码:

#include <iostream>using namespace std;long long n, ans;int main() {    while (cin >> n) {        ans = 1;        while (n > 1) {            n = n / 2;            ans++;        }        cout << ans << "\n";    }}


 

C jhljx学位运算

解题思路:

数组元素不改变,是静态的,因此可以用前缀和处理。假设原数据在nums数组中,用一个额外的数组prefix来存储前缀和,表示, 对于区间,所求答案即为

需要注意,输入的子数组边界不一定是的,如果需要先交换。

代码:

#include <iostream>using namespace std;const int MaxN = 1000000 + 7;int n, k, l, r;int nums[MaxN], prefix[MaxN];int main() {    while (cin >> n) {        prefix[0] = 0;        for (int i = 1; i <= n; i++) {            cin >> nums[i];            prefix[i] = prefix[i - 1] ^ nums[i]; //前缀和数组        }        cin >> k;        while (k--) {            cin >> l >> r;            if (l > r) swap(l, r); //需要特别注意            cout << (prefix[r] ^ prefix[l - 1]) << "\n";        }    }}


 

D 股票交易

解题思路:

题意即为求出满足的的最大值。

先读入所有元素,然后进行线性遍历。遍历到第i个元素时,记录下之前所有元素的最小值,与当前元素作对比,一方面维护最小值,另一方面更新差值即可。

代码:

#include <iostream>using namespace std;const int MaxN = 1000000 + 7;int n, det, num, Min;int main() {    while (cin >> n) {        det = -1;        Min = MaxN; //最小值        while (n--) {            cin >> num;            if (num <= Min)                Min = num; //维护最小值            else                det = max(det, num - Min); //更新差值        }        if (det < 0) cout << "No solution\n";        else cout << det << "\n";    }}


 

E 模式寻对

解题思路:

求逆序对个数,按理说复杂度为O(tnlogn)的代码很可能会超时,但是似乎没有复杂度更低的办法了,于是就这么做了,居然没有超时。

做法类似归并排序,求区间[l,r]中的逆序对个数,可以利用辅助空间先递归求出[l,mid)和[mid,r]区间里的逆序对个数,并分别完成排序,再从辅助空间回到主空间进行有序归并,归并的同时算出横跨mid两侧的逆序对的个数,三者求和就是总的逆序对个数。

代码:

#include <cstring>#include <cstdio>long long inv_pair(int a[], int n) {//统计a数组中前n个元素的逆序对数    if (n == 1 || n == 0) return 0;    long long sum = 0;    int mid = (n / 2);    sum += inv_pair(a, mid);    //递归求解左半段    sum += inv_pair(a + mid, n - mid);    //递归求解右半段    int *b = new int[n + 3];    //归并排序需要辅助空间    memcpy(b, a, n * sizeof(int));    for (int i1 = 0, i2 = mid, i = 0; i1 < mid || i2 < n; ++i) {        if (i2 == n) {            a[i] = b[i1];            ++i1;            sum += i2 - mid;        } else if (i1 == mid) {            a[i] = b[i2];            ++i2;        } else if (b[i1] <= b[i2]) {            a[i] = b[i1];            ++i1;            sum += i2 - mid;        } else {            a[i] = b[i2];            ++i2;        }    }    delete[] b;    return sum;}const int MaxN = 10000 + 7;int n, k, l, r;long long ans;int nums[MaxN], back[MaxN];int main() {    while (scanf("%d", &n) != EOF) {        for (int i = 0; i < n; i++) scanf("%d", &nums[i]);        scanf("%d", &k);        while (k--) {            scanf("%d%d", &l, &r);            memcpy(back, nums + l, (r - l + 1) * sizeof(int));            //切记要先复制到辅助空间内,否则影响之后的询问            ans = inv_pair(back, r - l + 1);            printf("%lld\n", ans);        }    }}


F 究极汉诺塔

解题思路:

关于汉诺塔有一个性质:从状态A到状态B的最少步数,和从状态B到状态A的最少步数是一样的。

汉诺塔的处理原则是先大后小。先考虑最大的一块盘子,想要搬动最大的一块,需要将这一块上面的盘子和目标位置上的盘子移到辅助柱上,设这些盘子都在辅助柱上的状态称为状态C,整个过程分为3步:

  1. 将当前状态移动至状态C
  2. 将最大的盘子从当前状态移动至目标柱
  3. 将状态C移动至所求的最终状态

 

代码:

#include <cstdio>const int MaxN = 65;int n, top, mid;long long ans;int pos[MaxN];int target[MaxN];inline long long hanoi(int step) {    return (1LL << (long long) step) - 1;}long long move(int stat[], int now, int tgt) {    if (now == 0) return 0;    else if (stat[now] == tgt) return move(stat, now - 1, tgt);    else return move(stat, now - 1, 6 - tgt - stat[now]) + hanoi(now - 1) + 1;}int main() {    while (scanf("%d", &n) != EOF && n) {        for (int i = 1; i <= n; i++)            scanf("%d", &pos[i]);        for (int i = 1; i <= n; i++)            scanf("%d", &target[i]);        top = n;        while (top >= 1 && pos[top] == target[top]) top--;        if (top > 0) {            mid = 6 - pos[top] - target[top];            ans = move(pos, top - 1, mid) + move(target, top - 1, mid) + 1;        } else ans = 0;        printf("%lld\n", ans);    }}


 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 喝酒脸上起了很多小红疙瘩怎么办 我的脸又痒又红怎么办 脸又红又痒又烫怎么办 满脸痘痘怎么办全部都是红的 身上起大片扁疙瘩很痒怎么办 我急用钱借钱又借不到怎么办 小孩蛀牙牙疼怎么办教你立刻止疼 牙齿里面长了个小牙齿怎么办 2岁宝宝又吐又拉怎么办 u盘坏了怎么办没反应了 怀孕了不知道孩子是谁的怎么办 怀孕八个月耻骨疼的厉害怎么办 没感情了这段婚姻该怎么办 1岁半宝宝o型腿怎么办 4s店没按时交车怎么办 几天几夜睡不着觉没有睡意怎么办 辣的吃多了胃疼怎么办 喉咙痛怎么办有最好即简单好得快 减肥过后皮肤留下的肥胖纹怎么办 用了完美玛丽艳脸上长痘痘怎么办 腰疼怎么办8方法解决腰疼 红米3x开不了机怎么办 苹果手机忘记了锁屏密码怎么办 小米5的4g网速慢怎么办 红米4a卡机了怎么办 信而富逾期3个月怎么办 苹果6锁屏密码忘了怎么办 孕8个月咳嗽有痰怎么办 微信红包输了6万怎么办 红米3s开不了机怎么办 核载5人载了6人怎么办 我欠支付宝2万6怎么办 我47岁这个月经不来怎么办 两个月不来月经了也没怀孕怎么办 婴儿不吃奶粉母乳又不够吃怎么办 怀孕39周了还没反应怎么办 脸过敏了又红又痒怎么办 刚开的淘宝店没生意怎么办 我22岁长得显老怎么办 卡的钱被qq转走怎么办 招行u盾密码忘了怎么办