week10 作业

A-签到题

题目描述

东东在玩游戏“Game23”。
在一开始他有一个数字n,他的目标是把它转换成m,在每一步操作中,他可以将n乘以2或乘以3,他可以进行任意次操作。输出将n转换成m的操作次数,如果转换不了输出-1。
Input
输入的唯一一行包括两个整数n和m(1<=n<=m<=5*10^8).
Output
输出从n转换到m的操作次数,否则输出-1.

样例

Simple Input 1
120 51840
Simple Output 1
7
Simple Input 2
42 42
Simple Output 2
0
Simple Input 3
48 72
Simple Output 3
-1

思路分析

首先m一定是n的倍数,得到m除以n的商赋给m,先除尽其中的6(即除尽了2或3),每除一次ans+2(一次2,一次3),若此时为奇数,3未除尽,再除尽3,ans++;否则为偶数,2未除尽,再除尽2,ans++。最后m应为1 。

AC代码

#include<iostream>
using namespace std;
//201820130210 
int main()
{
 int n,m;
 int ans=0;
 cin>>n>>m;
 if(m%n==0)//m是n的倍数 
 {
  m=m/n;
  while(m>=6)
  {
   if(m%6==0)
   {
    m=m/6;
    ans+=2;
   }
   else
       break;
  }
  if(m%2==1)//m因子有奇数,除尽3
  {
   while(m>=3)
   {
    if(m%3==0)
        {
        m=m/3;
        ans++;
       }
       else
           break;
   }
  }
        else
  {
   //再除尽2,最后m应该为1 
       while(m>=2)
      {
        if(m%2==0)
          {
           m=m/2;
           ans++;
          }
          else
              break;
      }
   }  
  if(m==1)  cout<<ans;
  else
      cout<<"-1"; 
 }
 else
     cout<<"-1";
 return 0;    
}

B - LIS & LCS

题目描述

东东有两个序列A和B。
他想要知道序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。
Input
第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)

第二行n个数,表示序列A

第三行m个数,表示序列B
Output
输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度。

样例输出

Simple Input
5 5
1 3 2 5 4
2 4 3 1 5
Simple Output
3 2

思路分析

LIS(最长上升子序列):n个整数Ai——An,从左到右选择尽量多的数,组成的一个升序序列。
LCS(最长公共子序列):两个序列A、B,从A、B中选出两个相同的子序列,使子序列尽可能长。

动态规划问题

使用课上学到的LIS、LCS的转移方程。数组LIS存放到A[i]的最长上升子序列的长度,LIS[1]=1,LIS[i]=max{LIS[i] | j<i&&Aj<Ai } +1,答案为max{LIS[i] }。
二维数组LCS存放到A[i],B[j]的最长公共子序列的长度。LCS[0][0]=LCS[0][1]=LCS[1][0],当A[i]==B[j]时,LCS[i][j]=LCS[i-1][j-1]+1;否则,LCS[i][j]=max(LCS[i][j-1],LCS[i-1][j])。答案为LCS[n][m]。

AC代码

#include<iostream>
#include <algorithm>
using namespace std;
int a[5010],b[5010],lis[5010],lcs[5010][5010];
int main()
{
 int n,m;
 cin>>n>>m;
 for(int i=1;i<=n;i++)
 {
  cin>>a[i];
 }
 for(int i=1;i<=m;i++)
 {
  cin>>b[i];
 }
 //
 lis[1]=1;
 for(int i=2;i<=n;i++)
 {
  int Max=0;
  for(int j=1;j<i;j++)
  {
   if(a[j]<a[i]&&lis[j]>Max) Max=lis[j];
  }
  lis[i]=Max+1;
 } 
 lcs[0][0]=lcs[1][0]=lcs[0][1]=0;
 for(int i=1;i<=n;i++)
 {
  for(int j=1;j<=m;j++)
  {
   if(a[i]==b[j]) lcs[i][j]=lcs[i-1][j-1]+1;
   else
   {
    lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
   }
  }
 }
 sort(lis+1,lis+n+1);
 cout<<lis[n]<<" "<<lcs[n][m];
 return 0;
 } 

C - 拿数问题 II

题目描述

YJQ 上完第10周的程序设计思维与实践后,想到一个绝妙的主意,他对拿数问题做了一点小修改,使得这道题变成了 拿数问题 II。

给一个序列,里边有 n 个数,每一步能拿走一个数,比如拿第 i 个数, Ai = x,得到相应的分数 x,但拿掉这个 Ai 后,x+1 和 x-1 (如果有 Aj = x+1 或 Aj = x-1 存在) 就会变得不可拿(但是有 Aj = x 的话可以继续拿这个 x)。求最大分数。

本题和课上讲的有些许不一样,但是核心是一样,需要你自己思考。

Input
第一行包含一个整数 n (1 ≤ n ≤ 105),表示数字里的元素的个数
第二行包含n个整数a1, a2, …, an (1 ≤ ai ≤ 105)
Output
输出一个整数:n你能得到最大分值。

样例

Input
2    
1 2    
Output   
2         
Input    
3     
1 2 3                
Output
4           
Input
9    
1 2 1 3 2 2 2 2 3
Output
10

思路分析

拿数问题 1
n个数A[1]到A[n],若拿走数A[i],则数A[i-1],A[i+1]不可拿,状态转移方程dp[i]=max(dp[i-1],dp[i-2]+A[i])。

拿数问题2
与1不同的是,若拿走数A[i],则数A[i]-1,A[i]+1不可拿。数组ans存能拿到的最大分数,则从ans[min{A[i]}]开始到ans[max{A[i]}],ans[i]= max(ans[i-1],ans[i-2]+A[i]),因为每个数出现不止一次,所以用数组num存每个数组出现的次数,所以最后的状态转移方程为ans[i]= max(ans[i-1],ans[i-2]+A[i]*num[A[i]])。

注意数组类型要是long long型,因为最后答案是拿数的和,若有10^5个10 ^5,将 超过int。

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long a[100001]={0};//元素 
long long num[100001]={0};//次数 
long long ans[100001]={0};//每一步的最大值
//如果有10^5个10 ^5,超过int
int main()
{ 
 int n;
 cin>>n;
 for(int i=1;i<=n;i++)
 {
  cin>>a[i];
  num[a[i]]++;
 }
 sort(a+1,a+n+1);
 long long Max=0;
 for(long long i=a[1];i<=a[n];i++)
 {
  ans[i]=max(ans[i-1],ans[i-2]+i*num[i]);
  Max=max(Max,ans[i]);
 }
 cout<<Max;
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rwyoi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值