Contest3381 - 2024寒假集训 进阶训练赛 (六)

目录

问题 A: 统计单词数

问题 B: 单词替换

问题 C: 生日相同

问题 D: 编程实现进制转换

问题 E: Stones

问题 F: Expedition

问题 G: 【蓝桥杯2021初赛】货物摆放

问题 H: 【蓝桥杯2021初赛】砝码称重

问题 I: 最小值-2019

问题 J: 不论你距我多远,哪怕刀山火海我愿为你走天下

问题 K: 跑图

问题 L: Ensemble’s heritage

问题 M: 剪切

问题 N: 数学?

问题 O: 数学!


问题 A: 统计单词数

题目描述

一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。

现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。

注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2)。

输入格式

2 行。
第 1 行为一个字符串,其中只含字母,表示给定单词;
第 2 行为一个字符串,其中只可能包含字母和空格,表示给定的文章。
字符串长度不超过1000

输出格式

只有一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从0开始);如果单词在文章中没有出现,则直接输出一个整数-1。

输入样例
To
to be or not to be is a question
输出样例
2 0
题解
#include <iostream>
#include <string>
using namespace std;

// 将字符串转化为小写形式
string lower(string s)
{
    int len = s.length();
    string res;
    for (int i=0; i<len; i++){
        if (s[i] <= 'Z' && s[i] >= 'A'){
            res += char(int(s[i]) + 32);
        }
        else {
            res += s[i];
        }
    }
    return res;
}

int main()
{
    string s1, s2;
    cin >> s1;
    int cnt = 0, len = 0;
    int pos;
    while (cin >> s2){
        if (lower(s2) == lower(s1)){
            cnt++;
            if (cnt == 1){
                pos = len;
            }
        }
        else {
            len += s2.length() + 1;
        }
    }
    if (cnt == 0){
        cout << -1;
        return 0;
    }
    cout << cnt << " " << pos;
    return 0;
}

问题 B: 单词替换

题目描述

输入一个字符串,以回车结束(字符串长度<=100)。该字符串由若干个单词组成,单词之间用一个空格隔开,所有单词区分大小写。现需要将其中的某个单词替换成另一个单词,并输出替换之后的字符串。

输入格式

输入包括3行,
第1行是包含多个单词的字符串 s;
第2行是待替换的单词a(长度 <= 100);
第3行是a将被替换的单词b(长度 <= 100).
s,a,b最前面和最后面都没有空格。

输出格式

输出只有 1 行,将s中所有单词a替换成b之后的字符串。

输入样例
You want someone to help you
You
I
输出样例
I want someone to help you
题解
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;   getline(cin, s);
    string a;   cin >> a;
    string b;   cin >> b;
    int i = 0, len = s.length();
    while (i < len){
        string word = "";
        while (i < len){
            if (s[i] == ' '){
                i++;
                break;
            }
            word += s[i++];
        }
        if (word == a){
            cout << b << " ";
        }
        else {
            cout << word << " ";
        }
    }
    return 0;
}

问题 C: 生日相同

题目描述

在一个有180人的大班级中,存在两个人生日相同的概率非常大,现给出每个学生的名字,出生月日。试找出所有生日相同的学生。

输入格式

第一行为整数n,表示有n个学生,n ≤ 180。此后每行包含一个字符串和两个整数,分别表示学生的名字(名字第一个字母大写,其余小写,不含空格,且长度小于20)和出生月(1 ≤ m ≤ 12)日(1 ≤ d ≤ 31)。名字、月、日之间用一个空格分隔

输出格式

每组生日相同的学生,输出一行,其中前两个数字表示月和日,后面跟着所有在当天出生的学生的名字,数字、名字之间都用一个空格分隔。对所有的输出,要求按日期从前到后的顺序输出。 对生日相同的名字,按名字从短到长按序输出,长度相同的按字典序输出。如没有生日相同的学生,输出”None”

输入样例
6
Avril 3 2
Candy 4 5
Tim 3 2
Sufia 4 5
Lagrange 4 5
Bill 3 2
输出样例
3 2 Tim Bill Avril
4 5 Candy Sufia Lagrange
题解
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;

struct data
{
    string name;
    int month, day;
};

struct stats
{
    vector<string> names;
    int month, day;
};


bool cmp(data a, data b)
{
    if (a.month == b.month){
        if (a.day == b.day){
            if (a.name.length() == b.name.length()){
                return a.name < b.name;
            }
            return a.name.length() < b.name.length();
        }
        return a.day < b.day;
    }
    return a.month < b.month;
}

int main()
{
    int n;  cin >> n;
    data students[n];
    for (int i=0; i<n; i++){
        cin >> students[i].name >> students[i].month 
            >> students[i].day;
    }
    sort(students, students + n, cmp);
    vector<stats> res;
    stats temp;
    temp.names.push_back(students[0].name);
    temp.month = students[0].month; temp.day = students[0].day;
    res.push_back(temp);
    int size = 1;
    for (int i=1; i<n; i++){
        if (students[i].day == res[size-1].day 
            && students[i].month == res[size-1].month){
            res[size-1].names.push_back(students[i].name);
        }
        else {
            stats t;
            t.names.push_back(students[i].name);
            t.month = students[i].month; 
            t.day = students[i].day;
            res.push_back(t);
            size++;
        }
    }
    bool isok = false;
    for (int i=0; i<size; i++){
        int k = res[i].names.size();
        if (k > 1){
            isok = true;
            cout << res[i].month << " " << res[i].day << " ";
            for (int j=0; j<k; j++){
                cout << res[i].names[j] << " ";
            }
            cout << endl;
        }
    }
    if (!isok){
        cout << "None";
    }
    return 0;
}

问题 D: 编程实现进制转换

题目描述

编程输入十进制整数N(N:-32767~32767),请输出它对应的二进制,八进制,十六进制数

输入格式

一个整数N

输出格式

输出一行三个数,分别代表这个数的二进制,八进制,十六进制,通过空格分隔

输入样例
2
输出样例
10 2 2
题解
#include <iostream>
#include <vector>
using namespace std;

vector<char> getIndexBase(int n, int index)
{
    vector<char> res;
    int i = 1;
    while (n){
        int temp = n % index;
        n /= index;
        if (temp <= 9 && temp >= 0){
            res.push_back(char(int('0') + temp));
        }
        else {
            res.push_back(char(int('a') + temp - 10));
        }
    }
    return res;
}

void printNum(vector<char> res, bool isNeg)
{
    int n = res.size();
    if (n == 0){
        cout << 0;
    }
    if (isNeg){
        cout << '-';
    }
    for (int i=n-1; i>=0; i--){
        cout << res[i];
    }
    cout << " ";
}

int main()
{
    int n;  cin >> n;
    bool isNeg = false;
    if (n < 0){
        isNeg = true;
    }
    if (isNeg){
        printNum(getIndexBase(-n, 2), isNeg);
        printNum(getIndexBase(-n, 8), isNeg);
        printNum(getIndexBase(-n, 16), isNeg);
    }
    else {
        printNum(getIndexBase(n, 2), isNeg);
        printNum(getIndexBase(n, 8), isNeg);
        printNum(getIndexBase(n, 16), isNeg);
    }
    return 0;
}

问题 E: Stones

题目描述

Because of the wrong status of the bicycle, Sempr begin to walk east to west every morning and walk back every evening. Walking may cause a little tired, so Sempr always play some games this time.
There are many stones on the road, when he meet a stone, he will throw it ahead as far as possible if it is the odd stone he meet, or leave it where it was if it is the even stone. Now give you some informations about the stones on the road, you are to tell me the distance from the start point to the farthest stone after Sempr walk by. Please pay attention that if two or more stones stay at the same position, you will meet the larger one(the one with the smallest Di, as described in the Input) first.

输入格式

In the first line, there is an Integer T(1<=T<=10), which means the test cases in the input file. Then followed by T test cases.
For each test case, I will give you an Integer N(0<N<=100,000) in the first line, which means the number of stones on the road. Then followed by N lines and there are two integers Pi(0<=Pi<=100,000) and Di(0<=Di<=1,000) in the line, which means the position of the i-th stone and how far Sempr can throw it.

输出格式

Just output one line for one test case, as described in the Description.

输入样例
2
2
1 5
2 4
2
1 5
6 6
输出样例
11
12
题解
#include <iostream>
#include <queue>
using namespace std;

struct stone
{
    int p, d;
    void getStone()
    {
        cin >> p >> d;
    }
    void putStone()
    {
        cout << p << " " << d << endl;
    }
};

struct cmp
{
    bool operator () (const stone &x, const stone &y) const
    {
        if (x.p == y.p){
            return x.d > y.d;
        }
        return x.p > y.p;
    }
};

int main()
{
    int t;  cin >> t;
    while (t--){
        int n;  cin >> n;
        priority_queue<stone, vector<stone>, cmp> stones;
        for (int i=0; i<n; i++){
            stone temp;
            temp.getStone();
            stones.push(temp);
        }
        int cnt = 1;
        int farthest;
        while (!stones.empty()){
            stone temp = stones.top();
            stones.pop();
            if (cnt % 2){
                temp.p += temp.d;
                stones.push(temp);
                farthest = temp.p;
                cnt++;
            }
            else {
                cnt++;
            }
        }
        cout << farthest << endl;
    }
    return 0;
}

问题 F: Expedition

题目描述

一群母牛抓住卡车,冒险进入从林深处。不幸的是,司机跑过一块岩石时,卡车的油箱被刺穿。现在,卡车每行驶一段距离,就会泄漏1单位燃油。要修理卡车,母牛需要沿着一条蜿蜓曲折的道路驶向最近的城镇(相距不超过 1000000 单位)。在这条道路上,在城镇和卡车的当前位置之间,有N个(1≤N≤10000)加油站,卡车可以停下来获取更多的燃料(每站1~100 单位)。
从林对人类来说是一个危险的地方,对母牛来说更为危险。因此,母牛希望在前往小镇的途中尽可能少地停下加油。幸运的是,卡车上的油箱容量很大,以至于可以容纳的燃油量实际上没有限制。卡车目前离镇区L单位,有P单位燃料 (1≤P≤1000000)。
确定到达城镇,或者母牛根本无法到达城镇所需的最少停靠站数。

输入格式

第1行:一个整数N。
第2~N+1行:每行包含两个以空格分隔的整数,用于描述加油站:第一个整数是从城镇到停靠站的距离;第二个整数是该站的可用燃料量。
第N+2行:两个以空格分隔的整数L和P。

输出格式

第一行:一个整数,给出到达城镇所需的最少燃料停止数量。如果无法到达城镇,则输出-1。

输入样例
4
4 4
5 2
11 5
15 10
25 10
输出样例
2
题解
#include <iostream>
#include <queue>
using namespace std;

struct station
{
    int distance;
    int gas;
    void GetStation()
    {
        cin >> distance >> gas;
    }
    void PutStation()
    {
        cout << distance << " " << gas << endl;
    }
};

struct cmp
{
    bool operator () (const station &a, const station &b) const
    {
        if (a.distance == b.distance){
            return a.gas < b.gas;
        }
        return a.distance < b.distance;
    }
};

int main()
{
    priority_queue<station, vector<station>, cmp> stations;
    int n;  cin >> n;
    for (int i=0; i<n; i++){
        station temp;
        temp.GetStation();
        stations.push(temp);
    }
    int l, p;   cin >> l >> p;
    priority_queue<int, vector<int>, less<int> > reachedStations;
    int cnt = 0;
    while (1){
        while (!stations.empty() && l - stations.top().distance <= p){
            reachedStations.push(stations.top().gas);
            stations.pop();
        }
        if (p >= l){
            break;
        }
        if (!reachedStations.empty()){
            p += reachedStations.top();
            reachedStations.pop();
            cnt++;
        }
        else {
            cout << -1;
            return 0;
        }
    }
    cout << cnt;
    return 0;
}

问题 G: 【蓝桥杯2021初赛】货物摆放

题目描述

小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有n 箱货物要摆放在仓库,每箱货物都是规则的正方体。
小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆L、W、H 的货物,满足n = L × W × H。
给定n,请问有多少种堆放货物的方案满足要求。
例如,当n = 4 时,有以下6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当n = 2021041820210418 (注意有16 位数字)时,总共有多少种
方案?

输入格式

输出格式

结果

题解
#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
#define ll long long

int main()
{
    ll n = 2021041820210418;
    vector<ll> list;
    for (ll i=1; i<=sqrt(n); i++){
        if (n % i == 0){
            list.push_back(i);
            list.push_back(n / i);
        }
    }
    sort(list.begin(), list.end());
    int len = list.size();
    ll cnt = 0;
    for (int i=0; i<len; i++){
        for (int j=i; j<len; j++){
            for (int k=j; k<len; k++){
                if (list[i] * list[j] * list[k] == n){
                    if (i == j && j == k){
                        cnt += 1;
                    }
                    else if (i == j || j == k){
                        cnt += 3;
                    }
                    else {
                        cnt += 6;
                    }
                }
            }
        }
    }
    cout << cnt;
    return 0;
}

问题 H: 【蓝桥杯2021初赛】砝码称重

题目描述

你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2, ... , WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数N。
第二行包含N 个整数:W1, W2, W3, ... , WN。
对于50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过100000。

输出格式

输出一个整数代表答案。

输入样例
3
1 4 6
输出样例
10
题解
#include <iostream>
using namespace std;

bool isok[100+5][100000+5]{};
int main()
{
    int n;
    cin >> n;
    int w[100+5];
    int sum = 0;
    for (int i=1; i<=n; i++){
        cin >> w[i];
        sum += w[i];
    }
    isok[0][0] = true;
    for (int i=1; i<=n; i++){
        for (int j=0; j<=sum; j++){
            isok[i][j] = isok[i-1][j] || isok[i-1][j+w[i]] 
                         || isok[i-1][abs(j-w[i])];
        }
    }
    int cnt = 0;
    for (int i=1; i<=sum; i++){
        if (isok[n][i]){
            cnt++;
        }
    }
    cout << cnt;
    return 0;
}

问题 I: 最小值-2019

题目描述

给定区间[l,r]
要求选出2个数i ,j
满足l <= i < j <= r
并且 (i * j) mod 2019 最小
并求出这个最小值
1 <= l < r <= 2e9

输入格式

l r

输出格式

最小值

输入样例
2020 2040
输出样例
2
题解
#include <iostream>
using namespace std;

int main()
{
    int l, r;   cin >> l >> r;
    if (r - l >= 2019){
        cout << 0;
        return 0;
    }
    l %= 2019;  r %= 2019;
    if (l > r){
        int p = r;
        r = l;
        l = p;
    }
    int minM = (l * r) % 2019;
    for (int i=l; i<r; i++){
        for (int j=l+1; j<=r; j++){
            minM = min(minM, (i * j) % 2019);
        }
    }    
    cout << minM;
    return 0;
}

问题 J: 不论你距我多远,哪怕刀山火海我愿为你走天下

题目描述

小T和她的男神位于一个二维坐标平面上,x和y轴的正方向分别是水平向右和竖直向上。
小T位于点(sx, sy),男神位于点(tx, ty),满足男神在小T的右上方。
小T到每次可以向上或向下或向左或向右移动一个单位,她要到他的身旁(tx, ty),再回到她自己原来的位置(sx, sy),再回到他的身旁(tx, ty),再回到自己原来的位置(sx, sy)。
请输出一种最短的走法,满足:除了(sx, sy)和(tx, ty)外,不经过同一个点两次。

输入格式

一行用空格隔开的4个整数sx, sy, tx, ty (-1000≤sx, sy, tx, ty≤1000)
代表小T的起始位置(sx, sy)和男神的位置(tx, ty)

输出格式

输出一种小T的合法路径,分别用UDLR来代表每一步的上下左右,具体可见样例及解释
请按样例的方式来走QAQ

输入样例
0 0 1 2
输出样例
UURDDLLUUURRDRDDDLLU
数据范围与提示

从(sx, sy)到(tx, ty):(0,0)->(0,1)->(0,2)->(1,2)
从(tx, ty)到(sx, xy):(1,2)->(1,1)->(1,0)->(0,1)
从(sx, sy)到(tx, ty):(0,0)->(-1,0)->(-1,1)->(-1,2)->(-1,3)->(0,3)->(1,3)->(1,2)
从(tx, ty)到(sx, xy):(1,2)->(2,2)->(2,1)->(2,0)->(2,-1)->(1,-1)->(0,-1)->(0,0)

题解
#include <iostream>
using namespace std;

int main()
{
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
    int width = x2 - x1;
    int height = y2 - y1;
    for (int i=0; i<height; i++)
        cout << 'U';
    for (int i=0; i<width; i++)
        cout << 'R';
    for (int i=0; i<height; i++)
        cout << 'D';
    for (int i=0; i<=width; i++)
        cout << 'L';
    for (int i=0; i<=height; i++)
        cout << 'U';
    for (int i=0; i<=width; i++)
        cout << 'R';
    cout << "DR";
    for (int i=0; i<=height; i++)
        cout << 'D';
    for (int i=0; i<=width; i++)
        cout << 'L';
    cout << 'U';
    return 0;
}

问题 K: 跑图

题目描述

给你一个N点M边的无向带权连通简单图(无向、带权、连通、无自环、无重边)
其中第i(1≤i≤M)条边连接点ai和bi,权重是ci
输出不属于任意两点的最短路径的边的条数。

输入格式
  • 2 ≤ N ≤ 100
  • N-1 ≤ M ≤ min(N(N-1)/2,1000)
  • 1 ≤ a_i, b_i ≤ N
  • 1≤c_i≤1000
  • c_i是整数
  • 给定的图没有自环也没有重边
  • 给定的图是连通图
输入格式

N M
a1 b1 c1
a2 b2 c2
...
am bm cm

输出格式

输出不属于任意两点的最短路径的边的条数。
即:如果点a和点b的最短路径经过了边c,那么c不是答案中的一条。

输入样例
3 3
1 2 1
1 3 1
2 3 3
输出样例
1
数据范围与提示

从点1到点2,最短路径是1->2,权重为1
从点2到点3,最短路径是2->3,权重为1
从点3到点1,最短路径是3->2->1,权重为2


所以第3条边(连接点1和点3,权重是3)不属于上面任何两点之间的最短路径,因此答案是1(条)。

题解
#include <iostream>
using namespace std;

struct edge
{
    int x, y;
    int len;
};

int main()
{
    int n, m;   cin >> n >> m;
    int road[n+1][n+1]{};
    edge path[m];
    for (int i=0; i<m; i++){
        int a, b, c;
        cin >> a >> b >> c;
        road[a][b] = road[b][a] = c;
        path[i].len = c;
        path[i].x = a;
        path[i].y = b;
    }
    for (int k=1; k<=n; k++){
        for (int i=1; i<=n; i++){
            for (int j=1; j<=n; j++){
                if (i != j && j != k && i != k){
                    if (road[i][j] && road[i][k] && road[k][j]){
                        road[i][j] = min(road[i][j], road[i][k] + road[k][j]);
                    }
                    else if(road[i][k] && road[k][j]){
                        road[i][j] = road[i][k] + road[k][j];
                    }
                }
            }
        }
    }
    int cnt = 0;
    for (int i=0; i<m; i++){
        if (road[path[i].x][path[i].y] < path[i].len){
            cnt++;
        }
    }
    cout << cnt;
    return 0;
}

问题 L: Ensemble’s heritage

题目描述

作为十三课的卢卡,是没有权力去直接审讯犯人的。所以卢卡就偷到了N张卡,监狱一共有M个房间。

第i个监狱的门可以由 第L,L+1,L+2, ... ,R张卡打开

但是卢卡的数学并不好,他想让你帮帮他,有几张卡能打开所有的门

输入格式
N M
L1 R1
L2 R2
L3 R3
... 
LN RN
1<=N<=1e5 1<=M<=1e5 1<=Li<=Ri<=N
输出格式

一个整数,代表答案

输入样例
4 2
1 3
2 4
​
输出样例
2
题解
#include <iostream>
using namespace std;

int main()
{
    int n, m;   cin >> n >> m;
    int left = 0, right = n;
    while (m--){
        int l, r;   cin >> l >> r;
        left = max(l, left);
        right = min(r, right);
    }
    int nums = right >= left ? right - left + 1 : 0;
    cout << nums;
    return 0;
}

问题 M: 剪切

题目描述

在一个二维坐标平面上,有一个四边形。
它的四个顶点的坐标分别是 ( 0 , 0 ) , ( W , 0 ) , ( W , H )和( 0 , H )

四边形内部(或边界上),有一个点。
它的坐标是( x , y )。

从这个点画一条直线,把四边形分成两个部分。
问你面积最小的那个部分的最大面积是多少。

同时,还要问你得到这个面积的划分方法数。

输入格式

.

输入一行4 44个空格隔开的正整数,具体意义见题目描述。

输入格式如下:

W H x y

其中:

  • 1 ≤ W , H ≤ 10^9
  • 0 ≤ x ≤ W
  • 0 ≤ y ≤ H
输出格式

.

输出一行空格隔开的两个数

  • 第一个数是划分成的两部分的面积最小的那部分的最大面积,7舍8入保留6位小数。
  • 第二个数代表划分成这个面积的方案,0代表只有一种划分方案,1代表有多种划分方案。
输入样例
2 3 1 2
输出样例
3.000000 0
数据范围与提示

样例一中,直线x = 1 将四边形划分为面积相等的两块儿,每一块儿的面积都是3,且只有这一种划分方案

题解
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    double w, h, x, y;
    cin >> w >> h >> x >> y;
    double s = w * h / 2.0;
    cout << fixed << setprecision(6) << s << " ";
    if (x == w / 2.0 && y == h / 2.0){
        cout << 1;
    }
    else {
        cout << 0;
    }
    return 0;
}

问题 N: 数学?

题目描述

Tisfy: 这是一道数学题?

给你长度为n的数组a和一个正整数k,问你a有多少个和大于等于k的连续子序列。

输入格式

.

第一行空格隔开的两个正整数,分别代表数组长度和要大于的数。

第二行n个空格隔开的正整数,代表数组a。

输入格式如下:

n k
a1 a2 ... an

其中:

  • 1 ≤ a_i ≤ 10^5
  • 1 ≤ n ≤ 10^5
  • 1 ≤ k ≤ 10^10
输出格式

.输出一行一个正整数代表数组a的 和大于等于k的连续子序列 的个数。

输入样例
4 10
6 1 2 7
输出样例
2
数据范围与提示

样例一中,
a [ 1..4 ]的和为6 + 1 + 2 + 7 = 16 ≥ 10 
a [ 2..4 ] 的和为1 + 2 + 7 = 10 ≥ 10

题解
#include <iostream>
using namespace std;

int main()
{
    long long n, k;   cin >> n >> k;
    long long a[n];
    for (long long i=0; i<n; i++){
        cin >> a[i];
    }
    long long cnt = 0, sum = a[0];
    long long l = 0, r = 0;
    while (r < n){
        if (sum >= k){
            cnt += n - r;
            sum -= a[l++];
        }
        else {
            sum += a[++r];
        }
    }
    cout << cnt;
    return 0;
}

问题 O: 数学!

题目描述

给你两个长度分别为n和m的数组S、T,问你S的子序列有多少和T的子序列相同。

此题子序列不要求连续,即:从序列a中删除0到len(a)个元素后得到的序列即为a的子序列。

输入格式

.

第一行空格隔开的两个正整数n和m,分别代表序列S的长度和序列T的长度。

第二行n个空格隔开的正整数,代表序列S。

第三行m个空格隔开的正整数,代表序列T。

输入格式如下:

n m
S1 S2 ... S3
T1 T2 ... T3

其中:

  • 1 ≤ n , m ≤ 2×10^3
  • 1 ≤ S_i , T_i ≤ 10^5
  • 所有输入的数都为正整数
输出格式

.输出一行一个正整数代表序列S和序列T的相同子序列的个数,答案对10^9+7取模。

输入样例
2 2
1 3
3 1
输出样例
3
数据范围与提示

样例一中,
序列S 有4 个子序列:( ) , ( 1 ) , ( 3 ) , ( 1 , 3 )
序列T 有4 个子序列:( ) , ( 3 ) , ( 1 ) , ( 3 , 1 ) 

相同子序列有3 33对:( ) , ( 1 ) , ( 3 )

题解
#include <iostream>
using namespace std;
#define ll long long
int main()
{
    ll n, m;   cin >> n >> m;
    ll s[n+5], t[m+5];
    for (ll i=1; i<=n; i++){
        cin >> s[i];
    }
    for (ll i=1; i<=m; i++){
        cin >> t[i];
    }
    ll mod = 1e9 + 7;
    ll cnt[n+1][m+1]{};
    for (int i=0; i<=n; i++){
        cnt[i][0] = 1;
    }
    for (int j=0; j<=m; j++){
        cnt[0][j] = 1;
    }
    for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            cnt[i][j] = cnt[i-1][j] + cnt[i][j-1];
            if (s[i] != t[j]){
                cnt[i][j] -= cnt[i-1][j-1];
            }
            cnt[i][j] = (cnt[i][j] + mod) % mod;
        }
    }
    cout << cnt[n][m];
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值