2022-02-14每日刷题打卡

132 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

2022-02-14每日刷题打卡

AcWing——算法基础

899. 编辑距离 - AcWing题库

给定 n 个长度不超过 10 的字符串以及 m 次询问,每次询问给出一个字符串和一个操作次数上限。

对于每次询问,请你求出给定的 n 个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。

每个对字符串进行的单个字符的插入、删除或替换算作一次操作。

输入格式

第一行包含两个整数 n 和 m。

接下来 n 行,每行包含一个字符串,表示给定的字符串。

再接下来 m 行,每行包含一个字符串和一个整数,表示一次询问。

字符串中只包含小写字母,且长度均不超过 10。

输出格式

输出共 m 行,每行输出一个整数作为结果,表示一次询问中满足条件的字符串个数。

数据范围

1≤n,m≤1000

输入样例:

3 2
abc
acd
bcd
ab 1
acbd 2

输出样例:

1
3

用字符串数组接收最初的字符串,再用后面每次询问的字符串和字符串数组中的字符串依次求最短编辑距离,如果最短编辑距离小于上限操作次数,计数器就++。对比全部完成后输出计数器。(最短编辑距离的求法可以看我昨天的打卡)

#include<iostream>
using namespace std;

const int N=1010;
string s[N];
int f[20][20];

int min_len(string s1,string s2)
{
    int n=s1.size(),m=s2.size();
    for(int i=0;i<=n;i++)f[i][0]=i;
    for(int i=0;i<=m;i++)f[0][i]=i;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
            f[i][j]=min(f[i][j],f[i-1][j-1]+(s1[i-1]==s2[j-1]?0:1));
        }
    }
    return f[n][m];
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)cin>>s[i];
    while(m--)
    {
        string str;
        int limit,res=0;
        cin>>str>>limit;
        for(int i=0;i<n;i++)
        {
            if(min_len(str,s[i])<=limit)res++;
        }
        cout<<res<<endl;
    }
    return 0;
}

282. 石子合并 - AcWing题库

设有 N 堆石子排成一排,其编号为 1,2,3,…,N。

每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。

每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。

例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 1、2 堆,代价为 4,得到 4 5 2, 又合并 1,2 堆,代价为 9,得到 9 2 ,再合并得到 11,总代价为 4+9+11=24;

如果第二步是先合并 2,3 堆,则代价为 7,得到 4 7,最后一次合并代价为 11,总代价为 4+7+11=22。

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入格式

第一行一个数 N 表示石子的堆数 N。

第二行 N 个数,表示每堆石子的质量(均不超过 1000)。

输出格式

输出一个整数,表示最小代价。

数据范围

1≤N≤300

输入样例:

4
1 3 5 2

输出样例:

22

设状态f[i] [j]为:从第i个石头到第j个石头,合并所需的最少代价。

我们想和并两堆石头,使其代价最少,那自然是要两边的石头都尽可能的小了,这里用的是分治的想法,比如我们想把5块石头1,2,3,4,5合并,我们直接到最后一步来,可能的结果是以2为分界点,1和2 3 4 5合并,也可以是以3为分界点,1 2和3 4 5合并……我们就这样枚举分界点,看以哪个点为分界点时,两边的值都尽可能的小,当我们找到了分界点后,比如假设这里的分界点是4,是1 2 3 4和5合并,那么我们我们在对1 2 3 4做重复操作(5只有一个石头就不需要了),由此以往得到最小的结果。为什么这里写的时候用到了前缀和,这其实是优化,我们知道,当最后两堆石头合并时,不管先前咋样,这最后一步的合并所需代价必然是所有石头一开始的总和,比如样例的1 3 5 2,最后一步所需代价就是1+3+5+2=11。我们在枚举分界点的时候,要计算分开后,合并石头的代价,我们经过分治,最后会使得左右两边只有一个石头,比如样例一开始的1 3合并,那么就是第一个数到第2个数的总和。以此类推……(如果没太搞懂也可能是我讲的太模糊,也可能是你不懂分治的思路),最后答案就在f[1] [n]上:第1个石头到第n个石头的总和。

#include<iostream>
using namespace std;

const int N=310;
int f[N][N];
int s[N];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i],s[i]+=s[i-1];
        
    }
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            f[i][j]=1e8;
            for(int k=i;k<j;k++)
            {
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
            }
        }
    }
    cout<<f[1][n]<<endl;
    return 0;
}

蓝桥杯——算法提高

算法提高 四数排序

问题描述

对四个非负整数从大到小排序后输出。

输入格式

一行四个非负整数。

输出格式

四行每行一个整数,从大到小顺序输出。

样例输入

1 2 3 4

样例输出

4

3

2

1

数据规模和约定

每个数不超过1e9.

这题为什么会是个算法提高的??算了正好给我摸鱼用。(这题注意点就是要用long long,不然会爆数据)

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>

typedef long long ll;

bool cmp(ll a, ll b)
{
    return a > b;
}


int main()
{
    vector<ll>v(4);
    for (int i = 0; i < 4; i++)cin >> v[i];
    sort(v.begin(), v.end(), cmp);
    for (int i = 0; i < 4; i++)cout << v[i] << endl;
    return 0;
}