LXH的暑假训练

记录了一个学生在暑假期间通过学习C++ STL、动态规划、二分法等算法,解决了一系列复杂问题的心路历程,包括洛谷平台上的多个题目解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

暑假学习

7/27
今天做了以前没有想出来的题目,自己就用C++的STL里面的map做出来ac了,然后看看大佬们的题解,用map的少不过继续努力吧。题目P1603

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
string a[6];
int main()
{
    map<string,string>secret;  //map容器映射,并且自带按照键值排序
secret.insert(make_pair("one","01"));secret.insert(make_pair("two","04"));
secret.insert(make_pair("three","09"));secret.insert(make_pair("four","16"));
secret.insert(make_pair("five","25"));secret.insert(make_pair("six","36"));
secret.insert(make_pair("seven","49"));secret.insert(make_pair("eight","64"));
secret.insert(make_pair("nine","81"));secret.insert(make_pair("ten","00"));
secret.insert(make_pair("eleven","21"));secret.insert(make_pair("twelve","44"));
secret.insert(make_pair("thirteen","69"));secret.insert(make_pair("fourteen","96"));
secret.insert(make_pair("fifteen","25"));secret.insert(make_pair("sixteen","56"));
secret.insert(make_pair("seventeen","89"));secret.insert(make_pair("eighteen ","24"));
secret.insert(make_pair("nineteen","61"));secret.insert(make_pair("twenty","00"));
secret.insert(make_pair("first","01"));secret.insert(make_pair("a","01"));
secret.insert(make_pair("another","01"));secret.insert(make_pair("both","04"));
secret.insert(make_pair("second","04"));secret.insert(make_pair("third","09"));
    string str; int i,len=0,flag=0,sum=0;
    while(cin>>str&&str[0]!='.')
    {    //find函数是个好东西
        if(secret.find(str)!=secret.end())  //如果没有找到则返回secret.end()迭代器
            {
                a[len++]=secret.find(str)->second; sum++;
            }
    }
    sort(a,a+len);
    if(sum==0) cout<<0; //这里没加只得了80分
    for(i=0;i<a[0].size();i++)
        if(a[0][i]=='0'&&flag)
          cout<<0;
        else if(a[0][i]!='0')
          flag=1,cout<<a[0][i];
    for(i=1;i<len;i++)
        cout<<a[i];
    return 0;
}

PS:很少用到STL里面的容器,因为自己做题太少了,很容易卡题,还是多做点自己不会的题目,多学习!


Date:7/28 今天学到了动态规划中求最大上升子序列问题:这是一种线性动态规划问题,比较简单容易理解。然后就做了洛谷里面的P1091
题解:合唱队形要求身高中间最高两边以此递减,这个问题很容易就理解。我们需要求出最大的序列。可以把问题分开来看,先求从左往右升序列,然后求从右往左的降序列,最后两个相加得出dp1[i]+dp2[i]-1(因为dp1和dp2都包括了A[i]这个数所以要减)就是合唱团人数最多的序列

#include<iostream>
#include<algorithm>
using namespace std;
int a[105],dp1[105],dp2[105];
int main()
{
    int n,i,j,MAX=-1;
    cin>>n;
    for( i=0;i<n;i++)
       cin>>a[i];
    for(i=0;i<n;i++){
        dp1[i]=1;
      for(j=0;j<i;j++)
      if(a[i]>a[j])
        dp1[i]=max(dp1[i],dp1[j]+1);
    }//求最大上升子序列
    for(i=n-1;i>=0;i--){
        dp2[i]=1;
      for(j=n-1;j>i;j--)
      if(a[i]>a[j])
        dp2[i]=max(dp2[i],dp2[j]+1);
    }//求最大下降子序列
    for(i=0;i<n;i++)
      MAX=max(MAX,dp1[i]+dp2[i]);   //计算出最大的序列(为谋取最大先升后降的序列)
    cout<<n-MAX+1;
    return 0;
}

PS:今天开始入手比较难的动态规划,还是多写多练才能行啊!


7/28 下午做了一道以前望而生畏的二分题 洛谷P1182 数列分段

这题和N本书分成连续的M组,使每一组书厚度之和最小 这样的经典例题有着异曲同工之妙
思路:利用二分的思想求最大数列和,但是L却不能取得0或者1,因为我一直在第四个点wa就很烦。所以L就取得了最大值,R取得了sum总和。
还是自己二分用的太少了,judge函数里面cnt从0开始就错了!!!

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=100000+5;
int a[maxn],n,m,Max=-1;
long long sum=0;
bool judge(long long num)
{
    long long cnt=1,t=num; //一定要记住!!!!cnt从1开始
    for(int i=0;i<n;i++)
        if(t>=a[i])
          t-=a[i];
        else
          cnt++,t=num-a[i];   //若装不下去则新增一个序列去装入
     return cnt<=m;       //判断mid是否过大
}
long long Binary_find()
{
    long long l=Max,r=sum,mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(judge(mid))   //满足分成m段数列:若mid导致所截数组cnt<=m,则r=mid;
            r=mid;
        else
            l=mid+1;    //cnt>m,表示所选mid过小
    }
    return r;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
            Max=max(Max,a[i]);
        }
    /*cout<<sum<<endl;*/
    cout<<Binary_find();
    return 0;
}

PS:还是得去细细品味cnt和m的关系,以及judge函数中为什么r=mid(目的是若mid过大了,使右边界左移 ),judge函数还是从书中看见的,这种思路模板得记住,这题写了也多加深二分法的思想。


7/30 根据看了动态规划里面的LCS和LIS问题,我自己想着动手去写一个dp题目试试,然后找到了这个**洛谷P1802 **
类似与背包问题,就想着写了一下,加深记忆和代码构架

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Node{
  int use,lose,win;
}a[1000+5];
long long dp[1000+5];      ///最后一个数据没有写long long导致数据溢出
int main()
{
    int n,x,i,j;
    cin>>n>>x;
    for(i=0;i<n;i++)
      scanf("%d%d%d",&a[i].lose,&a[i].win,&a[i].use);
    for(i=0;i<n;i++)
      for(j=x;j>=0;j--)
        if(j>=a[i].use)   ///这里别忘了,不然会出大问题
          dp[j]=max(dp[j]+a[i].lose*5,dp[j-a[i].use]+a[i].win*5);
        else
          dp[j]=max(dp[j]+a[i].lose*5,dp[j]);
    cout<<dp[x];
    return 0;
}

PS:刚开始这题只得了90分,然后把数据下下来一看,数据溢出了。所以改了个long long,最终ac了。


7/31 经过了这几天的动态规划的训练,脑袋中有了一些关于动态规划的一些思路和想法,的确动态规划能够实际解决许多问题,利用贪心和动态规划做题目然后ac的确让人快乐!
这题使洛谷P1616 这题就是可以无限次的装入同一样物品

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e4+5,maxdp=1e7+5;
int m,t,i,j; long long dp[maxdp];
struct Node{
  int t,value;
}a[maxn];
int main()
{
   cin>>t>>m;
   for(i=0;i<m;i++)
    scanf("%d%d",&a[i].t,&a[i].value);
   for(i=0;i<m;i++)
    for(j=0;j<=t;j++)  ///j从0开始代表一个草药可以装无数次
      if(j>=a[i].t)
        dp[j]=max(dp[j],dp[j-a[i].t]+a[i].value);
   cout<<dp[t];
}

8/1 今天就8月一日了,时间都过去一半了。今天还是一直在看动态规划,不得不说看的头皮发麻,动态规划题目还是很难啊尤其是状态转移太费脑细胞了!!!!! 今天做了一道dp题目 还是很有意思的 洛谷P1002

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
unsigned long long dp[25][25]={0};
int main()
{
    int x1,y1,x2,y2,flag=1;
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    for(int i=1,j=0;i<=x1;i++)
       {
            if((fabs(i-x2)+fabs(j-y2)==3&&fabs(i-x2)&&fabs(j-y2))||(fabs(i-x2)==fabs(j-y2)&&fabs(j-y2)==0))
                dp[i][j]=0,flag=0;      ///如果dp[i][j]马挡住,则后面的路全为0
            else if(flag)
                dp[i][j]=1/*,cout<<dp[i][j]*/;
       }
    flag=1;
    for(int i=0,j=1;j<=y1;j++)
       {
            if(((fabs(i-x2)+fabs(j-y2)==3&&fabs(i-x2)&&fabs(j-y2))||(fabs(i-x2)==fabs(j-y2)&&fabs(j-y2)==0)))
                dp[i][j]=0,flag=0;    ///同理
            else if(flag)
                dp[i][j]=1/*,cout<<dp[i][j]*/;
       }
     for(int i=1;i<=x1;i++)
       {
        for(int j=1;j<=y1;j++)
           if((fabs(i-x2)+fabs(j-y2)==3&&fabs(i-x2)&&fabs(j-y2))||(fabs(i-x2)==fabs(j-y2)&&fabs(j-y2)==0))
            dp[i][j]=0;
          else
            dp[i][j]=dp[i-1][j]+dp[i][j-1];
         }
    cout<<dp[x1][y1];
}///这题主要思路是dp[i][j]=dp[i-1][j]+dp[i][j-1]
///因为卒只能向右走或者向下走,因此dp[i][j]只能从dp[i-1][j]向下走,或者dp[i][j-1]向右走而来

思路:这题目以前在B站看过类似的题目,思路还是比较清晰的
//状态转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1] //
找到了这个方程解题目还是挺容易的,但是的注意在i=1或者j=1时如果有马在上面或者马能够挡住这条路,则后面的路全为0。就是没有想到这里最后两个数据点wa了,下了数据才发现!哎吐了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值