Vj程序设计作业H5

A : 巨石迷阵

问题描述

听说这片土地埋藏着什么秘密,来到这片土地的人不计其数,有人说这里财宝无数,也有人说这里是上古文明留下来的遗迹。小 L 收集情报和资料很久了,只身一人历经千辛万苦终于来到了这片地域的中心地带。突然,四周升起许多巨石,不出所料,面前的正是巨石迷阵。

你面前有 n 块巨石排成一行,每个上面有一个大写字母。
接下来有 m 个询问,每一个询问包含两个数字 l,r ,对于每个询问,你需要回答这个处于区间 [l,r] 的石块上的字母是否每一个英文字母都至少出现了一次。

输入格式

第一行一个整数 n , n≤5×105
第二行,一个长度为 n 的字符串
第三行,一个整数 m, m≤5×105
接下来的 m 行,每行两个整数表示 l,r,1≤l≤r≤n

输出格式

输出包含 m 行,每行一个 YES ,或者 NO 。
分别表示是否每个字母都至少出现一次。

样例输入

30
AAABCDEFGHIJKLMNOPQRSTUVWXYZAA
5
1 26
2 27
3 28
4 29
5 30

样例输出

NO
NO
YES
YES
NO

解答

#include <bits/stdc++.h>

using namespace std;
int b[500001][26];

int main()
{
    int n;
    cin >> n;
    char a[n];
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (i == 0)
        {
            b[i + 1][a[i] - 'A']++;
        }
        else
        {
            for (int j = 0; j < 26; j++)
            {
                b[i + 1][j] = b[i][j];
                if (j == a[i] - 'A')
                {
                    b[i + 1][j]++;
                }
            }
        }
    }
    int m;
    cin >> m;
    for (int i = 1; i <= m; i++)
    {
        int l, r;
        cin >> l >> r;
        int j = 0;
        for (; j < 26; j++)
        {
            int x = b[r][j] - b[l - 1][j];
            if (x <= 0)
            {
                cout << "NO" << endl;
                break;
            }
        }
        if (j >= 26)
        {
            cout << "YES" << endl;
        }
    }
    return 0;
}

B : 有惊无险

问题描述

解决了巨石迷阵,小 L 长舒一口气。他坐在一棵繁茂的树下刚打开地图,突然,四周轰隆隆又一阵巨响,面前又出现了许多巨石。

情报有误!情报有误!!

根据搜集来的情报,这里不应该再次出现这么多巨石!
小 L 赶忙起身,屏气凝神,重新专注起来...

有一个长度为 n 的字符串,找到一个区间 [l,r],使得处于区间 [l,r] 的石块上的字母,26 个大写字母都至少出现一次。输出这个区间长度的最小值。

数据保证有解

输入格式

第一行一个整数 n , n≤2×105
第二行,一个长度为 n 的字符串

输出格式

一行,一个数,代表最短长度

样例输入

30
AABBCDEFGHIJKLMNOPQRSTUVWXYZZZ

样例输出

27

解答

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    cin >> n;
    char a[n];
    int g = n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int b[26] = {0};
    int l = 0, r = 25;
    for (int i = 0; i < 26; i++)
    {
        int y = a[i] - 'A';
        b[y]++;
    }
    while (1)
    {
        if (r - l < 25)
        {
            // if (r == n - 1)
            // {
            //     break;
            // }
            r++;
            b[a[r] - 'A']++;
        }
        else
        {
            int j = 0;
            for (; j < 26; j++)
            {
                if (b[j] <= 0)
                {
                    break;
                }
            }
            if (j == 26)
            {
                if (g > (r - l + 1))
                {
                    g = r - l + 1;
                }
                b[a[l] - 'A']--;
                l++;
            }
            else
            {
                r++;
                if (r > n - 1)
                {
                    r = n - 1;
                    b[a[l] - 'A']--;
                    l++;
                }
                else
                    b[a[r] - 'A']++;
            }
        }

        if (r == n - 1 && (r - l) < 25)
        {
            break;
        }
    }
    cout << g << endl;
    return 0;
}

C : 天降甘霖

问题描述

不知道又走了几天,眼前是一片整齐的青石地砖。不管是谁看上一眼,就知道这绝对不是自然生成的。当小 L 踏上青石地板的一瞬间,原本晴朗的天空迅速暗了下来。紧接着乌云密布,下起了雨。雨很快就停了,紧接着天空瞬间放晴,开始升温。潮湿的青石板被很快晒干。

“这是夏天了吗,雨来得快去得也快啊。”长时间孤身一人,小 L 经常自言自语。

但敏锐的 小 L 发现,有一些青石板上的痕迹没有被完全晒干,雨痕竟然拼成了数字。

有 一行 n 个数。输出每 k 个相邻数字的最大值和最小值。

输入格式

第一行两个整数 n,k, 1≤k≤n≤106
第二行,有 n 个数字,中间用空格隔开,每一个数为大小不超过 109 的正整数。

输出格式

有两行,每行 n−k+1 个数字,第一行表示最小值,第二行表示最大值。

样例输入

8 3
1 3 -1 -3 5 3 6 7

样例输出

-1 -3 -3 -3 3 3
3 3 5 5 6 7

 解答

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, k;
    cin >> n >> k;
    pair<int, long long> a[n + 1];
    long long min[n] = {0};
    int s = 0;
    for (int i = 1; i <= n; i++)
    {
        a[i].first = i;
        long long g = 0;
        cin >> g;
        a[i].second = g;
    }
    deque<pair<int, long long>> q;
    for (int i = 1; i <= k; i++)
    {
        while (1)
        {
            if (q.empty() || q.back().second < a[i].second)
            {
                q.push_back(a[i]);
                break;
            }
            else
            {
                q.pop_back();
            }
        }
    }
    min[s] = q.front().second;
    s++;
    for (int i = k + 1; i <= n; i++)
    {
        while (1)
        {
            if (q.empty() || q.back().second < a[i].second)
            {
                q.push_back(a[i]);
                break;
            }
            else
            {
                q.pop_back();
            }
        }
        while (1)
        {
            int c = (q.front()).first;
            if (c < i - k + 1)
            {
                q.pop_front();
            }
            else
            {
                break;
            }
        }
        min[s] = q.front().second;
        s++;
    }
    for (int i = 0; i < s; i++)
    {
        cout << min[i] << " ";
    }
    cout << endl;

    long long max[n] = {0};
    int ss = 0;
    // deque<pair<int, int>> q1;
    q.clear();
    for (int i = 1; i <= k; i++)
    {
        while (1)
        {
            if (q.empty() || q.back().second > a[i].second)
            {
                q.push_back(a[i]);
                break;
            }
            else
            {
                q.pop_back();
            }
        }
    }
    max[ss] = q.front().second;
    ss++;
    for (int i = k + 1; i <= n; i++)
    {
        while (1)
        {
            if (q.empty() || q.back().second > a[i].second)
            {
                q.push_back(a[i]);
                break;
            }
            else
            {
                q.pop_back();
            }
        }
        while (1)
        {
            int c = (q.front()).first;
            if (c < i - k + 1)
            {
                q.pop_front();
            }
            else
            {
                break;
            }
        }
        max[ss] = q.front().second;
        ss++;
    }
    for (int i = 0; i < ss; i++)
    {
        cout << max[i] << " ";
    }
    cout << endl;
    return 0;
}

D : 终而复始

问题描述

青石板路的尽头堆满了财宝。小 L 感到很一阵阵失望,只能先搬走一部分财宝了。

财宝是一个个矩形紧紧挨在一起,第 i 个矩形宽度为 1 ,高度是 hi​

小 L 是一个 不会贪心 不贪心的人,所以决定只拿走最大矩形的面积这么多。

拿着拿着,小 L 突然想到,其实这个财宝墙后面还是有路的。

输入格式

第一行一个整数 n , n≤105
第二行,一行数,第 i 个数代表 hi​ , 0≤hi​≤109

输出格式

一行,一个数,代表最大矩形面积

样例输入

7
2 1 4 5 1 3 3 

样例输出

8

解答

#include <bits/stdc++.h>

using namespace std;

int n;
stack<pair<int, long long>> s;
long long a[1000100], L[1000010], R[1000010];
// 寻找左边第一个小于该值的数的索引
void Find(long long Ans[])
{
    while (!s.empty())
    { // 清空栈
        s.pop();
    }
    for (int i = 1; i <= n; i++)
    {
        while (!s.empty() && s.top().second >= a[i])
        {
            s.pop();
        }
        if (s.empty())
        {
            Ans[i] = i;
        }
        else
        {
            Ans[i] = i - s.top().first;
        }

        s.push(pair<int, long long>(i, a[i]));
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    long long Ans = 0;
    Find(L);
    reverse(a + 1, a + n + 1);
    Find(R);
    reverse(a + 1, a + n + 1);
    reverse(R + 1, R + n + 1);
    for (int i = 1; i <= n; i++)
    {
        Ans = max(Ans, a[i] * (L[i] + R[i] - 1));
    }
    cout << Ans << endl;
    return 0;
}

E : 旅途不止

问题描述

小 L 至今没有回来。这太正常,就像其他没有回来的探险者一样。没有人会提起小 L ,也没有人述说小 L 的故事。
多年以后,你也踏上了这片神秘的土地,眼前出现了一道谜题。

有一列长度为 n 的数,初始值都是 1 。
有 m 次操作,每次对属于区间 [l,r] 的数都乘上一个数 cb ,最后输出这 n 个数的最大公约数。

谜题面前有一张地图,上面署名 "小 L"。

输入格式

第一行一个整数 n , n≤105
第二行,一个整数 m, m≤105 接下来的 m 行,每行四个整数表示 l,r,c,b 1≤l≤r≤n,1≤c≤100,0≤b≤109

输出格式

一行,一个数,代表最大公约数,答案对 109+7 取模。

样例输入

5
3
1 4 3 2
2 4 2 2 
3 5 6 1 

样例输出

3

初始:[1,1,1,1,1]
第一次操作后,[9,9,9,9,1]
第二次操作后,[9,36,36,36,1]
第三次操作后,[9,36,216,216,6] gcd(9,36,216,216,6)=3,gcd 表示最大公约数

地图上画的正是当年小 L 探索过的区域,但小 L 去了哪里还是不得而知。
地图的背面,写着如下内容:

n 个数的最大公约数求法:

设第 i 个数为 ai​,则 ai​=∏j​pjbij​​,其中 pj​ 表示第 j 个素数,bij​ 表示第 i 个数质因数分解之后 pj​ 的幂次。
则 gcd(a1​,...,an​)=∏j​pjminbij​​。

举例求 gcd(60,24,36,42) 60=22×31×51×70 24=23×31×50×70 36=22×32×50×70
42=21×31×50×71

所以

gcd(60,24,36,42)​=2min(2,3,2,1)×3min(1,1,2,1)×5min(1,0,0,0)×3min(0,0,0,0)=21×31×50×70=6​

解答 

#include <bits/stdc++.h>

using namespace std;
long long dd[100001][100];
// 质数判断
bool prime(long long a)
{
    if (a == 1)
    {
        return false;
    }
    else if (a == 2)
    {
        return true;
    }

    for (long long i = 2; i * i <= a; i++)
    {
        if (a % i == 0)
        {
            return false;
        }
        else
        {
            continue;
        }
    }
    return true;
}
// 快速幂计算并取模
long long P(long long x, long long n, long long mod)
{
    long long r = 1;
    while (n)
    {
        if (n & 1)
        {
            r = (r * x) % mod;
        }
        x = (x * x) % mod;
        n = n >> 1;
    }
    return r;
}

int main()
{
    long long n, m, max = 0;
    cin >> n >> m;
    long long res = 1;
    // 初始化
    for (long long i = 0; i < n + 1; i++)
    {
        for (long long j = 0; j < 100; j++)
        {
            dd[i][j] = 0;
        }
    }
    // m次操作
    for (long long i = 1; i <= m; i++)
    {
        long long l, r, c, b;
        cin >> l >> r >> c >> b;
        if (prime(c))
        { // c为质数
            dd[l - 1][c] += b; // 使用差分进行记录多次操作之后次方数
            dd[r][c] -= b;
            if (max < c) // 寻找最大的质因数,用于之后的寻找最大质因数
            {
                max = c;
            }
        }
        else
        { // c不为质数,将c转化为多个质数
            for (long long p = 2; p <= c; p++)
            {
                if (prime(p))
                {
                    while (c % p == 0)
                    {
                        dd[l - 1][p] += b;
                        dd[r][p] -= b;
                        c = c / p;
                        if (max < p)
                        {
                            max = p;
                        }
                    }
                }
            }
        }
    }
    for (long long i = 2; i <= max; i++)
    {
        long long k = 0;
        long long min = dd[0][i];
        for (long long j = 0; j < n; j++)
        {
            k = k + dd[j][i];
            if (min > k)
            {
                min = k;
            }
        }
        res = res * P(i, min, 1000000007) % 1000000007;
    }
    cout << res << endl;
    return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值