记录week10的实验两道题+作业三道题

签到题、LIS & LCS、 拿数问题 II、签到题、东东转魔方

作业:
签到题:

题意:
在一开始他有一个数字n,他的目标是把它转换成m,在每一步操作中,他可以将n乘以2或乘以3,他可以进行任意次操作。输出将n转换成m的操作次数,如果转换不了输出-1。

思路是:将m除以n,判断是否能整除,若能则继续除以三,不能就除以二,直到最后,如果能除尽了就ok(要用longlong

#include<bits/stdc++.h>
using namespace std;
int ans;
void solve(){
	long long int n,m;cin>>n>>m;	
	if(m%n){
	  ans=-1;
	} 
	else{
		long long int a=m/n;
		while(a%3==0)ans++,a=a/3;
		while(a%2==0)ans++,a=a/2;
		if(a!=1)
			ans=-1;
	}
}
int main(){
	solve();
	cout<<ans<<endl;
	return 0;
}

LIS&LCS:

两个序列A和B。

输出序列A的LIS和序列AB的LCS的长度。

注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。

这是一道动态规划的经典题目,具体思想就是动态规划的做法。
LIS:复杂度nlogn。对蓄序列进行遍历,遍历每个元素的时候对这个元素及其之前的所有元素挨个进行如下判断
if(A[i]>A[j]) Lis[i]=max(Lis[i],Lis[j]+1);
LCS:复杂度mn。其实这道题我们可以用递归的方法,但是递归的方法就像斐波那契亚数列,存在太多重复项,我们可能多次求某一个函数,牺牲了空间换取时间。这道题我们用记忆化的做法,也即是递推的做法做。我觉得之所以可以这么做是因为,后面的用得到前面的,前面的用不到后面的,也就是每一步得到的都是最优的。


	  if(A[i]==B[j])
	    Lcs[i+1][j+1]=Lcs[i][j]+1;	
	  else
	  	Lcs[i+1][j+1]=max(Lcs[i][j+1],Lcs[i+1][j]);

假设两个序列AB分别为:
A:0 5 6 4 2 7 8
B:2 3 4 5 6 8
令LCS[ i ]为到从开始一直到 i 位置的最长子序列长度
假设我们当前位于LCS[ 7 ][ 6 ],即A中的8和B中的8,这俩相等,所以它的长度就是LCS[ 7 ][ 6 ]=LCS[ 6 ][ 5 ]+1,若将B中的8换成9即
B:2 3 4 5 6 9
则LCS[ 7 ][ 6 ]=max( LCS[ 7 ][ 5 ],LCS[6][6])
递归会有重复,所以用递推即可求得最优解。

#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
int n,m;
long long int A[maxn],B[maxn];
long long int Lis[maxn];
long long int Lcs[maxn][maxn];
 

int main(){
cin>>n>>m;
for(int i=0;i<n;i++)cin>>A[i],Lis[i]=1;
for(int i=0;i<m;i++)cin>>B[i]; 


long long int ans1=0;
for(int i=0;i<n;i++)
for(int j=0;j<=i;j++)
{
	if(A[i]>A[j])
	   Lis[i]=max(Lis[i],Lis[j]+1);
	ans1=max(ans1,Lis[i]);
}
memset(Lcs,0,sizeof(Lcs));
for(int i=0;i<n;i++)
{
	for(int j=0;j<m;j++)
	{
	  if(A[i]==B[j])
	  {
	    Lcs[i+1][j+1]=Lcs[i][j]+1;	
	  }
	  else
	  {
	  	Lcs[i+1][j+1]=max(Lcs[i][j+1],Lcs[i+1][j]);
	  }
	}
}
long long int ans2=Lcs[n][m];
cout<<ans1<<" "<<ans2<<endl;

	
	return 0;
}

拿数问题II:

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

这一题,我们用一个数组cnt存一下每个次出现的频率,然后就可以用和课上的做法类似的做法,利用递推的方式,和上一题类似。以ans[i]表示到i为止可以拿的最大的分数。 i拿了 i-2就可以拿了,所以是ans[i]=max(ans[i-1],cnt[i]*i+ans[i-2]);

#include<iostream>
#include<algorithm> 
using namespace std;
#define maxn 100005
long long int A[maxn];
long long int cnt[maxn];
long long int ans[maxn];
int main(){
int n;cin>>n;
long long int maxnum=0;
for(int i=0;i<n;i++)cin>>A[i],maxnum=max(A[i],maxnum),cnt[A[i]]++;
long long int re;
ans[0]=0;ans[1]=cnt[1];

for(int i=2;i<=maxnum;i++)
{
   ans[i]=max(ans[i-1],cnt[i]*i+ans[i-2]);   
}

re=ans[maxnum];
cout<<re<<endl;
	return 0;
}

实验:
签到题:

东东有一个字符串X,该串包含偶数个字符,一半是 S 字符,一半是 T 字符
东东可以对该字符串执行 1010000 次操作:如果存在 ST 是该串的子串,则删除掉最左边的 ST。
即 TSTTSS⇒TTSS、SSSTTT⇒SSTT⇒ST⇒空

这道题就是用栈解决,依次将元素压栈,如果栈顶是S,下一个是T就pop,否则就push即可。

#include<bits/stdc++.h>
using namespace std;
stack<char>q;
string s;
int main(){
	cin>>s;
int i=1;q.push(s[0]);
while(i<s.size())
{
   if(q.empty())q.push(s[i]),i++;
   if(q.top()=='S'&&s[i]=='T'&&!q.empty())
   {
     	q.pop();
     	i++;
   }
   else
   {
   	  q.push(s[i]);
   	  i++;
   }	 
}
cout<<q.size()<<endl;	
	return 0;
}

东东转魔方:
原题链接
一道模拟题,这次是模拟一个222的魔方,看看能不能转90度使他六面相同。
模拟题做了很多次了,但是还是容易出问题,主要是思路出问题,很早之前之前的扑克牌和这次的魔方都是思路出了问题,我想的是判断条件是否满足,而不是去模拟一个魔方模拟一个牌,问题就出在这,进行条件的判断很容易漏条件,或是条件写错而且表达式很长,而模拟魔方只需要判断最终条件是否满足即可简单得多。牢记!

#include<bits/stdc++.h>
using namespace std;
int T,f,a[25],b[25],x[25];
int ok()
{
   int i=1;
   while(i<22)
   {
   	  for(int j=i+1;j<i+4;j++)
   	  {
   	  	 if (x[j]!=x[i]) return 0;
		 }
		 i=i+4;
   } 
    return 1;
}
int okk()
{
    int i=1;
   while(i<22)
   {
   	  for(int j=i+1;j<i+4;j++)
   	  {
   	  	 if (b[j]!=b[i]) return 0;
		 }
		 i=i+4;
   } 
    return 1;
    return 1;
}
void z1()
{

    x[20]=a[6];x[18]=a[5];
    x[5]=a[23];x[6]=a[21];
	x[21]=a[15];x[23]=a[16];
    x[16]=a[18];x[15]=a[20];    
}
void z2()
{
  
    x[14]=a[2];x[16]=a[4];
    x[10]=a[14];x[12]=a[16];
    x[2]=a[6];x[4]=a[8];
    x[8]=a[12];x[6]=a[10];    
}
void z3()
{ 
    x[20]=a[4];x[19]=a[3];
    x[9]=a[20];x[10]=a[19];
	x[3]=a[23];x[4]=a[24];
    x[24]=a[9];x[23]=a[10];    
}
int ok1()
{
    for (int i=1;i<=24;i++) a[i]=b[i];
    for (int i=1;i<=24;i++) x[i]=a[i];
    z1(); 
    if (ok()) return 1;
    for (int i=1;i<=24;i++) a[i]=x[i];
    z1();//再转两次 等于倒着转一次 
    for (int i=1;i<=24;i++) a[i]=x[i];
    z1();
    if (ok()) return 1;
    return 0;
}
int ok2()
{
    for (int i=1;i<=24;i++) a[i]=b[i];
    for (int i=1;i<=24;i++) x[i]=a[i];
    z2();
    if (ok()) return 1;
    for (int i=1;i<=24;i++) a[i]=x[i];
    z2();
    for (int i=1;i<=24;i++) a[i]=x[i];
    z2();
    if (ok()) return 1;
    return 0;
}
int ok3()
{
    for (int i=1;i<=24;i++) a[i]=b[i];
    for (int i=1;i<=24;i++) x[i]=a[i];
    z3();
    if (ok()) return 1;
    for (int i=1;i<=24;i++) a[i]=x[i];
    z3();
    for (int i=1;i<=24;i++) a[i]=x[i];
    z3();
    if (ok()) return 1;
    return 0;
}
int main()
{
    cin>>T;
    while (T--)
    {
        f=0;
        for (int i=1;i<=24;i++) cin>>b[i];
        if (okk()) f=1;
        if (f==0) if (ok1()) f=1;
        if (f==0) if (ok2()) f=1;
        if (f==0) if (ok3()) f=1;
        if (f==1) cout<<"YES"<<endl;else cout<<"NO"<<endl;
    }
    return 0;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值