2024年暑假ACM集训第5场

A: 道具的魅力值

题目描述

在某网络游戏中提供了一个道具库,在道具库中每种道具均有若干件(数量已知),游戏玩家购买一件道具将获得一定的魅力值。
已知每种道具的价格和魅力值,请编写一个程序,在总价格不超过某个上限的情况下使得所购道具的魅力值之和达到最大。

输入

每组测试数据的输入有n+1行,n表示道具的种类。(n<=100,p<=10000)
第1行包含两个正整数,分别表示道具种类数n和总价值的上限p,两个数字之间用空格隔开。
第2行到第n+1行分别对应于第1种道具到第n种道具的信息,每1行包含三个正整数,两个数字之间用空格隔开,三个正整数分别表示某一种道具的数量、单个道具的价格和魅力值。

输出

每组测试数据的输出只有一行,即道具魅力值的最大和。

样例输入 Copy
3 10
2 2 3
1 5 10
2 4 12
样例输出 Copy
27
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
const int inf =0x3fffffff;
const double PI = acos(-1.0);
struct S{
    int u,v,w;
}a[105];
bool cmp(S x,S y){
    return (double)x.w/x.v>(double)y.w/y.v;
}
void solve(){
    int n,p;
    while(cin>>n>>p){
        for(int i=0;i<n;i++){
            cin>>a[i].u>>a[i].v>>a[i].w;
        }
        sort(a,a+n,cmp);
        int s=0;
        for(int i=0;i<n;i++){
            int ss=min(a[i].u,p/a[i].v);
            s+=ss*a[i].w;
            p-=ss*a[i].v;
        }
        cout<<s<<"\n";
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 B: 最少数字

题目描述

小明用计算机随机生成了N个正整数,他希望从这N个数中选取若干个数,使得它们的和等于M。这些随机生成的数字可能会相同,但是每个数字最多只允许使用一次。
当然这样的选取方案可能不存在,也可能有多个。
现在希望你编写一个程序,能够找出数字个数最少的选取方案,输出对应的最少数字的个数,如果无解输出“No solution”。

输入

单组输入,每组输入2行。
第1行包含两个正整数N和M,分别表示初始输入的正整数个数和目标数字和(N<=1e3, M<=1e5)。
第2行为N个正整数,两两之间用空格隔开(每一个正整数均小于等于1e5)。

输出

输出数字个数最少的选取方案中所包含的最少数字个数,如果无解输出“No solution”。

样例输入 Copy
5 5
1 3 2 1 1
样例输出 Copy
2
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <fstream>
using namespace std;
typedef long long ll;
const int N = 1e3 +5;
const int M = 1e5 +5;
const int inf = 0x3fffffff;
int a[N];
int dp[M];
void solve(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        dp[i]=inf;
    }
    for(int i=1;i<=n;i++){
        for(int j=m;j>=a[i];j--){
            dp[j]=min(dp[j],dp[j-a[i]]+1);
        }
    }
    if(dp[m]==inf){
        cout<<"No solution\n";
    } 
    else{
        cout<<dp[m]<<"\n";
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //ofstream mycout("dabiao.txt");
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 C: 神奇的青蛙

题目描述

有一只神奇的青蛙,它最擅长的是跳格子,而且每次它跳的格数都满足2^k(k>=0)。
现在这只青蛙站在第1个格子里面,它如果想要跳到第N个格子,一共有多少种不同的跳法呢?

输入

单组输入。
每个测试样例输入1行,包含一个正整数N。(N<=1000)

输出

输出不同的跳法总数。

样例输入 Copy
5
样例输出 Copy
6
提示

当N=5时,一共有六种不同的跳法,分别如下:
1-->2-->3-->4-->5
1-->2-->3-->5
1-->2-->4-->5
1-->3-->4-->5
1-->3-->5
1-->5

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cmath>
using namespace std;
long long a[1005];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    a[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        a[i] = 0;
        for (int k = 0; k <= log2(i - 1); k++)
            a[i] += a[i - (int)pow(2, k)];
    }
    cout << a[n] << '\n';
    return 0;
}

 D: 小h的新游戏

题目描述

小h最近喜欢玩一款游戏,游戏中扮演的是一个法师,法师使用一张法术牌会对boss造成一定的伤害,法术牌并不会消耗掉可以重复使用,如果把boss的血量打到0代表胜利,而如果小于0则boss会复活并对你造成99999999点伤害,你就输了。小h发现有多种胜利的方案,但是他找不完全,所以他来寻求你的帮助

输入

第一行两个数字n和m表示拥有的法术牌的数量以及boss的血量
后n行每行一个数字表示法术牌对boss造成的伤害
(n<=100,m<=1000)

输出

击败boss的方案数(使用的牌种类或数量不同代表不同方案,改变牌的使用顺序同样代表不同方案,结果对(1e9+7)取余)

样例输入 Copy
1 3
1
样例输出 Copy
1
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n,m;
    cin>>n>>m;
    vector<int> a(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    vector<ll> dp(m+1,0);
    dp[0]=1;
    for(int i=1;i<=m;i++){
        for(int j=0;j<n;j++){
            if(i-a[j]>=0){
                dp[i]=(dp[i]+dp[i-a[j]])%M;
            }
        }
    }
    cout<<dp[m]<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 E: 小h的消息加密

题目描述

小h最近看了谍战电影,对里面消息的加密方式很感兴趣,他决定和朋友试一试,小h给朋友两个序列,两个序列的最长公共单调递增子序列就是要传递的消息,有时候序列太长了,小h的朋友找不出来,所以他找到了你

输入

第一个数字n表示序列长度
后面两行每行n个数字表示小h给出的两个序列
(n<=1000)

输出

输出需要传递的原序列的长度 

样例输入 Copy
3
1 2 3
3 1 2
样例输出 Copy
2
提示

需要传递的是1 2这个子序列

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <fstream>
using namespace std;
typedef long long ll;
const int N = 1e3 +5;
const int M = 1e9 +7;
const int inf = 0x3fffffff;
int a[N],b[N];
int dp[N][N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i]; 
    }
    for(int i=1;i<=n;i++){
        cin>>b[i];
    }
    for(int i=1;i<=n;i++){
        int m=1;
        for(int j=1;j<=n;j++){
            if(a[i]!=b[j]){
                dp[i][j]=dp[i-1][j];
            }
            if(a[i]==b[j]){
                dp[i][j]=max(m,1);
            }
            if(a[i]>b[j]){
                m=max(m,dp[i-1][j]+1);
            }
        }
    }
    int s=0;
    for(int i=1;i<=n;i++){
        s=max(s,dp[n][i]);
    } 
    cout<<s<<"\n";
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //ofstream mycout("dabiao.txt");
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 F: 完美序列

题目描述

已知一个长度为l的序列:b1,b2,b3,…,bl (1<=b1<=b2<=b3<=…<=bl<=n)。若这个序列满足每个元素是它后续元素的因子,换句话说就是对于任意的i (2<=i<=l)都满足bi%bi-1=0 (其中“%”代表求余),则称这个序列是完美的。你的任务是对于给定的n和l,计算出一共有多少序列是完美序列。由于答案很大,所有输出答案对1000000007取余后的结果。

输入

输入的第一行为一个正整数T (T<=1000),代表一共有T组测试数据。

每组测试数据包含两个正整数n,l (1<=n, l<=2000),分别代表序列中元素值上限和序列的长度。

输出

对于每组测试数据,输出一行包含一个整数,代表答案对1000000007取余后的结果。

样例输入 Copy

3
3 2
6 4
2 1
样例输出 Copy
5
39
2
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <sstream>
using namespace std;
typedef long long ll;
const int N =2e3 +5;
const int M =1e9 +7;
const int inf =0x3fffffff;
const double PI = acos(-1.0);
ll dp[N][N];
void solve(){
    int n,l;
    cin>>n>>l;
    ll s=0;
    for(int i=1;i<=n;i++){
        s=(s+(dp[l][i]%M))%M;
    }
    cout<<s<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    for(int i=1;i<N;i++){
        dp[1][i]=1;
    }
    for(int i=2;i<N;i++){
        for(int j=1;j<N;j++){
            for(int k=j;k<N;k+=j){
                dp[i][k]+=(dp[i-1][j]%M)%M;
            }
        }
    }
    int t;cin>>t;while(t--)
    solve();
    return 0;
}

 G: 一群X星人

题目描述

一群X星人围坐一圈,每个人手里都拿着一个数字卡片。这些卡片上的数字都是整数,但是有正有负。
你能否编写一个程序,计算出哪几个相邻的X星人他们手中卡片上的数字之和最大?

输入

单组输入,输入两行。
第1行表示X星人的数量n。(n<=1000)
第2行输入n个X星人手中卡片上的整数值,两个数字之间用空格隔开。

输出

输出相邻若干个X星人手中卡片上数字之和的最大值。

样例输入 Copy
5
10 -5 8 -4 2
样例输出 Copy
16
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <fstream>
using namespace std;
typedef long long ll;
const int N = 1e3 +5;
const int M = 1e9 +7;
const int inf = 0x3fffffff;
int a[N];
int dp[N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int s=-inf;
    for(int i=1;i<=n;i++){
        dp[i]=max(dp[i-1]+a[i],a[i]);
        s=max(dp[i],s);
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        a[i]=-a[i];
    }
    int m=0;
    int mm=-inf;
    for(int i=1;i<=n;i++){
        m=max(m+a[i],a[i]);
        mm=max(mm,m);
    }
    s=max(s,sum-(-mm));
    cout<<s<<"\n";
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //ofstream mycout("dabiao.txt");
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 H: 游戏装备

题目描述

小明最近迷上了一款英雄对战游戏。每个玩家可以拥有m个英雄,在游戏中提供了n件装备给英雄使用。不同的英雄拥有不同数目的装备时将获得不同的攻击值,每一个英雄可以拥有0件或多件装备。
请问如何分配这n件装备,可以使得所有m个英雄获得的攻击值的和最大?

输入

单组输入。
第1行输入两个正整数m和n,分别表示英雄的个数和装备的数量,两个数字之间用空格隔开。m和n均不超过100。
接下来是一个m*n的矩阵,第i行j列表示第i个英雄拥有j件装备时能够得到的攻击值(不拿武器默认0攻击力)。矩阵一共m行,每一行n列,同一行两个数字之间用空格隔开。

输出

输出m个英雄的攻击值之和的最大值。

样例输入 Copy
2 3
5 6 7
7 8 9
样例输出 Copy
1
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n,m;
    cin>>m>>n;
    vector<vector<int>> a(m,vector<int>(n+1,0));
    for(int i=0;i<m;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    vector<vector<int>> dp(m+1,vector<int>(n+1,-inf));
    dp[0][0]=0;
    for(int i=0;i<m;i++){
        for(int j=0;j<=n;j++){
            if(dp[i][j]>=0){
                for(int k=0;k<=n-j;k++){
                    dp[i+1][j+k]=max(dp[i+1][j+k],dp[i][j]+a[i][k]);
                }
            }
        }
    }
    int s=*max_element(dp[m].begin(),dp[m].end());
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

I: 山峦叠嶂

题目描述

小明很久很久没有爬过山了,这一天终于爬上了著名的X峰。站在X峰山顶,远处山峦叠嶂,让人感到心旷神怡。
小明看着远处一座座高山,突发奇想。如果按照从左到右的顺序告诉你n座山峰的海拔高度,最少去掉几座山峰,可以让剩下的山峰从左到右能够按照从矮到高的顺序排列呢?
【输入保证每一座山峰的海拔高度都不一样】。

输入

单组输入,输入占两行。
第1行一个正整数表示山峰数量n(n<=1e5,山峰高度<=1e5)。
接下来一行是n座山峰的高度,全部为正整数,两个数字之间用空格隔开。

输出

输出最少需要去掉的山峰数量。

样例输入 Copy
5
1265 2368 3474 2170 3982
样例输出 Copy
1
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <fstream>
using namespace std;
typedef long long ll;
const int N = 1e5 +5;
const int M = 1e9 +7;
const int inf = 0x3fffffff;
int a[N];
int dp[N];
void solve(){
    int n;
    cin>>n;
    int len=1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        dp[i]=inf;
    }
    dp[1]=a[1];
    for(int i=2;i<=n;i++){
        int l=0,r=len;
        if(a[i]>dp[len]){
            dp[++len]=a[i];
        }
        else{
            while(l<r){
                int mid=(l+r)>>1;
                if(dp[mid]>=a[i]){
                    r=mid;
                }
                else{
                    l=mid+1;
                }
            }
            dp[l]=min(a[i],dp[l]);
        }
    }
    cout<<n-len<<"\n";
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //ofstream mycout("dabiao.txt");
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 J: X星人矩阵

题目描述

一群X星人组成了一个N行M列的二维矩阵,每个X星人手中都拿着一块白板,每块白板上面都写着一个整数,有正整数、负整数也有0。
现在需要从这个X星人矩阵中找出一个小矩阵,要求这个小矩阵中所有人白板上的数字之和最大。
请输出这个小矩阵中所有数字的和。

输入

单组输入。
第1行输入两个正整数N和M,表示矩阵的行数和列数,N和M均不超过100,二者之间用空格隔开。
接下来N行,每行包含M个整数,对应X星人组成的二维矩阵,每行的整数两两之间均用空格隔开。

输出

输出一个整数,对应和最大的小矩阵的所有数字之和。

样例输入 Copy
4 4
1 -1 0 1
1 -1 2 1
-1 -2 -1 1
1 1 0 1
样例输出 Copy
5
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M =1e9 +7;
const int N =1e2 +5;
int a[N][N];
int s[N][N];
int b[N];
void solve(){
    int m,n;
    cin>>m>>n;
     
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    } 
    int sum=a[1][1];
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            s[i][j]=s[i-1][j]+a[i][j];
        }
    } 
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            int ss=0;
            for(int k=1;k<=n;k++){
                b[k]=s[j][k]-s[i-1][k];
            }
            for(int k=1;k<=n;k++){
                ss+=b[k];
                if(ss>sum){
                    sum=ss;
                }
                else if(ss<0){
                    ss=0;
                }
            }
        }
    }
    cout<<sum<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 K: X星人的宝藏

题目描述

X星人发现了一个藏宝图,在藏宝图中标注了N个宝库的位置。这N个宝库连成了一条直线,每个宝库都有若干枚金币。
X星人决定乘坐热气球去收集金币,热气球每次最多只能飞行M千米,但是热气球在飞行过程中并不会发生故障。
此外,由于设计上的缺陷,热气球最多只能启动K次。
X星人带着热气球来到了第1个宝库(达到第1个宝库时热气球尚未启动),收集完第1个宝库的金币后将启动热气球前往下一个宝库。如果他决定收集某一个宝库的金币,必须停下热气球,收集完之后再重新启动热气球。当然,X星人每到一个宝库是一定会拿走这个宝库所有金币的。
已知每一个宝库距离第1个宝库的距离(单位:千米)和宝库的金币数量。
请问X星人最多可以收集到多少枚金币?

输入

单组输入。
第1行输入三个正整数N、M和K,分别表示宝库的数量、热气球每次最多能够飞行的距离(千米)和热气球最多可以启动的次数,三个正整数均不超过100,相邻两个正整数之间用空格隔开。
接下来N行每行包含两个整数,分别表示第1个宝库到某一个宝库的距离(千米)和这个宝库的金币枚数。(因为初始位置为第1个宝库,因此第1个宝库所对应行的第1个值为0。)
输入保证所有的宝库按照到第1个宝库的距离从近到远排列,初始位置为第1个宝库。

输出

输出一个正整数,表示最多可以收集的金币数。

样例输入 Copy
5 10 2
0 5
8 6
10 8
18 12
22 15
样例输出 Copy
25
提示

X星人启动热气球两次,分别收集第1个、第3个和第4个宝库的金币,一共可以得到的金币总数为5+8+12=25枚。

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    int n,m,k;
    cin>>n>>m>>k;
    vector<int> a(n+1),b(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
    }
    vector<vector<int>> dp(n+1,vector<int>(k+1,-inf));
    dp[1][0]=b[1];
    int s=0;
    for(int i=2;i<=n;i++){
        for(int j=1;j<i;j++){
            if(a[i]-a[j]<=m){
                for(int z=1;z<=k;z++){
                    dp[i][z]=max(dp[i][z],dp[j][z-1]+b[i]);
                    s=max(s,dp[i][z]);
                }
            }
        }
    }
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 L: 回文数变换

题目描述

所谓回文数就是一个数字,从左边读和从右边读的结果都是一样的,例如12321。 
现在有一个只包含1、2、3、4的数字,你可以通过在任意位置增加一位数字或者删除一位数字来将其变换成一个回文数。但是增加或删除不同数字所需要的代价是不一样的。
已知增加和删除每个数字的代价如下:
增加一个1,代价:100;删除一个1,代价:120。
增加一个2,代价:200;删除一个2,代价:350。
增加一个3,代价:360;删除一个3,代价:200。
增加一个4,代价:220;删除一个4,代价:320。
请问如何通过最少的代价将一个数字变换为一个回文数。当然,如果一个数字本身已经是一个回文数(包括一位数,例如:2),那么变换的代价为0。

输入

单组输入。
输入一个由1、2、3、4组成的正整数,正整数位数<=100位。【提示:采用字符串输入】

输出

输出一个整数,表示将输入数字变换为一个回文数所需的最少代价。

样例输入 Copy
12322
样例输出 Copy
300
提示

增加一个1并增加一个2,将输入正整数变为1223221或者2123212,所需代价最小,为:100+200=300。

#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
int a[]={0,100,200,360,220};
int b[]={0,120,350,200,320};
int dp[105][105];
string s;
int dfs(int l,int r){
    if(r<=l){
        return 0;
    }
    if(dp[l][r]==0){
        if(s[l]==s[r]){
            dp[l][r]=dfs(l+1,r-1);
        }
        else{
            int x=s[l]-'0';
            int y=s[r]-'0';
            dp[l][r]=min({dfs(l+1,r)+a[x],dfs(l+1,r)+b[x],dfs(l,r-1)+a[y],dfs(l,r-1)+b[y]});
        }
    }
    return dp[l][r];
}
void solve(){
    cin>>s;
    int n=s.size();
    cout<<dfs(0,n-1)<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 M: 小明的难题

题目描述

小明最近遇到了一个比较头疼的问题:
现在有一串无序的正整数,允许你修改其中一个数字,使得修改之后得到一个长度最长的单调递增子序列。例如:4 1 2 2 1 4 3。你可以将第4个数字“2”改为“3”(也可以将第5个数字“1”改为“3”),这样可以得到长度为4的单调递增子序列。(在单调递增子序列中后一个数字都要严格大于前一个数字)。
请你编写一个程序,计算一个序列修改其中某一个数字之后可以得到的最长单调递增子序列的长度。

输入

单组数据。
第1行输入序列中数字个数N。(N<=1000)
第2行输入N个正整数,两个正整数之间用空格隔开(1<=正整数<=1e8)。

输出

输出修改输入序列中某一个数字之后可以得到的最长单调递增子序列的长度。

样例输入 Copy
7
4 1 2 2 1 4 3
样例输出 Copy
4
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N =1e6 +5;
const int M = 1e9 +7;
const int inf =0x3fffffff;
int a[N],dp[N];
void solve(){
    int n;
    cin>>n;
    int len=1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        dp[i]=inf;
    }
    dp[1]=a[1];
    for(int i=2;i<=n;i++){
        int l=0,r=len;
        if(a[i]>dp[len]){
            dp[++len]=a[i];
        }
        else{
            while(l<r){
                int mid=(l+r)>>1;
                if(dp[mid]>=a[i]){
                    r=mid;
                }
                else{
                    l=mid+1;
                }
            }
            dp[l]=min(a[i],dp[l]);
        }
    }
    if(len==n){
        cout<<n<<"\n";
    }
    else{
        cout<<len+1<<"\n";
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 N: 木箱子

题目描述

现在有很多木箱子,每一个箱子都是标准的长方体并且都是空心的。如果一个木箱子的长、宽和高都大于(不能等于)另一个木箱子,则小的箱子可以套到大的箱子里面。(注意:此处不考虑材质本身的厚度,且每一个木箱子在嵌套的时候长、宽、高都不允许旋转)
现在告诉你一些长方体木箱子的长、宽和高,请问这些木箱子最多可以嵌套多少层?

输入

单组输入。
第1行输入一个正整数N,表示长方体木箱子的总数量。(N<=1000)
接下来N行每行包含三个正整数,两两之间用空格隔开,分别表示每一个长方体木箱子的长、宽和高。(长、宽、高均小于等于10000。)

输出

输出一个正整数,表示木箱子最多可以嵌套的层数。

样例输入 Copy
4
1 2 3
3 6 3
2 3 4
3 4 5
样例输出 Copy
3
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
struct S{
    int x,y,z;
    bool operator<(const S &i)const{
        if(i.x==x){
            if(i.y==y){
                return z<i.z;
            }
            return y<i.y;
        }
        return x<i.x;
    }
};
void solve(){
    int n;
    cin>>n;
    vector<S> a(n);
    for(int i=0;i<n;i++){
        cin>>a[i].x>>a[i].y>>a[i].z;
    }
    sort(a.begin(),a.end());
    vector<int> dp(n,0);
    int s=0;
    for(int i=0;i<n;i++){
        dp[i]=1;
        for(int j=0;j<i;j++){
            if(a[i].x>a[j].x&&a[i].y>a[j].y&&a[i].z>a[j].z){
                dp[i]=max(dp[i],dp[j]+1);
            }
            s=max(s,dp[i]);
        }
    }
    cout<<s<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 O: 最长回文子串

题目描述

回文子串是指字符串的一个子串,这个子串从左往右和从右往左均一样,例如“ABBA”和“ABCBA”。
对于一个由大写英文字母和“*”号组成的字符串,求它的最长回文子串的长度,其中一个“*”号可以用来替代任意一个字符。
例如:字符串“AB*B*AC”的最长回文子串的长度为6,当第1个“*”号为“B”,第2个“*”号也为“B”时,可以得到一个回文子串“ABBBBA”。
输入一个包含大写英文字母和至少一个“*”号的字符串,请输出最长回文子串的长度。

输入

单组输入。
输入1行,包含一个由若干大写英文字母和至少一个“*”号组成的字符串,其长度小于等于1000。

输出

输出一个正整数,表示可以得到的最长回文子串的长度。

样例输入 Copy
DAB*B*ACD
样例输出 Copy
6
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 1e3+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
void solve(){
    string s;
    cin>>s;
    int n=s.size();
    int m=1;
    vector<vector<bool>> dp(n,vector<bool>(n,false));
    for(int i=0;i<n;i++){
        dp[i][i]=true;
    }
    for(int i=0;i<n-1;i++){
        if(s[i]==s[i+1]||s[i]=='*'||s[i+1]=='*'){
            dp[i][i+1]=true;
            m=2;
        }
    }
    for(int k=3;k<=n;k++){
        for(int i=0;i<=n-k;i++){
            int j=i+k-1;
            if(s[i]==s[j]||s[i]=='*'||s[j]=='*'){
                dp[i][j]=dp[i+1][j-1];
                if(dp[i][j]){
                    m=k;
                }
            }
        }
    }
    cout<<m<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值