签到题
思路
- 对于n每次都有乘以2和乘以3的的选择,利用递归。
- 当操作的结果等于m的时候,那么意味着能够转换,输出操作次数。
- 当操作的结果大于m的时候,意味着本次转换失败。
总结
在一开始的时候,需要对n和m进行判断,如果n==m,那么转换次数是0。并且如果n>m,那么意味着肯定不能成功转换。
代码
#include<iostream>
using namespace std;
int s=0;
int n = 0, m = 0;
int tag = 0;
void fun(int x,int ts) {
if (x == m) {
if(tag==0)cout << ts;
tag = 1; return;
}
else if (x > m)return;
fun(x * 2, ts + 1);
fun(x * 3, ts + 1);
}
int main() {
// while (1)
// {
cin >> n >> m;
s = 0; tag = 0;
if (n > m) cout << "-1" ;
else if (m == n) cout << "0";
else{
fun(n, s);
if (tag == 0) cout << "-1";
}
// }
return 0;
}
LIS&LCS
思路
LIS
- 对于数组a中的LIS,用f[i]记录以a[i]为结尾的最长上升序列长度,初始时,f数组置0。
- 当i>1时,对于以ai结尾的最长上升序列,可以分为两部分,ai以前的+ai本身。用j遍历1,2,……i-1,找到所有aj<ai,这些以aj为结尾的最长上升子序列 = 能够放在ai前的所有合乎条件的序列,这些序列的最大长度+1即为以ai为结尾的最长上升子序列的长度。
- 对于i=1时,f1=1
- 对于i>1,fi=max{fj | j<i ^ aj<ai }+1
LCS
-
对于数组a和数组b的LCS,用dp(i,j)记录a1,a2……ai 和 b1,b2……bj的LCS,初始时,dp数组置0。
-
对于i遍历j,i的范围为数组a的大小,j的范围为数组b的大小
-
如果ai == bj,那么a1,a2……ai-1和b1,b2……bj-1的LSC长度加上1即为dp(i,j)
上图中dp[i][j]=dp[i-1][j-1]+1 -
如果ai != bj
总结
理解了来用,这种思路挺方便的。先计算出子问题的解,然后再进行选择。
代码
#include<stdio.h>
#define range 5000+10
#include<string.h>
#include<algorithm>
using namespace std;
int a[range],b[range],f[range],dp[range][range];
int n=0,m=0;
int LIS(int arr[],int n){
memset(f,0,sizeof(f));
f[1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
if(arr[j]<arr[i]){
f[i]=max(f[i],f[j]);//找最大
}
}
f[i]++;//加自己
}
// for(int i=1;i<=n;i++) printf("f%d ",f[i]);
sort(f,f+n+1);
return f[n];
}
int LCS(int arr1[],int arr2[],int tn,int tm){
int i=0,j=0;
for(i=0;i<=tn;i++)
for(j=0;j<=tm;j++)
dp[i][j]=0;
for(i=1;i<=tn;i++){
for(j=1;j<=tm;j++){
if(arr1[i]==arr2[j])//a的第i个和b的第j个相等
dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
// for(i=0;i<=tn;i++){
// for(j=0;j<=tm;j++){
// printf("%d ",dp[i][j]);
// }
// printf("\n");
// }
return dp[tn][tm];
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
printf("%d",LIS(a,n));
printf(" %d",LCS(a,b,n,m));
return 0;
}
拿数问题II
思路
- 上课讲的是对于ai-2,ai-1,ai,ai+1,拿了ai,则ai-1和ai+1就不能拿。dp[i]为考虑a[1],a[2]……a[i]能拿到的最大分数,dp数组里的最大值即为答案。
初始时,dp数组置0。
当i=1时,dp[i] = 1;
当i>=2时,dp[i]如下图;
- 对于本题,只是修改了拿了某个数之后的影响。
- 对于数i-2,i-1,i,i+1,拿完了i(即没有i),则i-1和i+1就不能拿。
- 同样使用dp数组,dp[i]为考虑1,2,……i能拿到的最大分数,初始时置为0.
- 用一个vis数组记录a数组里的数的情况,vis[i]=5,代表有数组a中有5个i。
- i=1时,dp[1]=i*vis[1]
i>=2时,如下图
- 最终结果为dp数组里的最大值
总结
long long啊!!!,又忘记了/(ㄒoㄒ)/~~
代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define range 100000+10
using namespace std;
long long a[range],vis[range];
long long dp[range];//对数i
int n=0;
long long fun(){
dp[1]=1*vis[1];
for(int i=2;i<=range;i++){
//不拿,dp[i-1]
//拿,拿vis[i]个,i-2 i-1 i
dp[i]=max(dp[i-1],dp[i-2]+i*vis[i]);
}
sort(dp,dp+range);
return dp[range-1];
}
int main()
{
scanf("%lld",&n);
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
vis[a[i]]++;//个数
}
printf("%lld",fun());
return 0;
}