5.4代码

目录

1.本质上升序列

最长回文串(回顾一下)

最长子序列问题

本题解法

2.排列距离


1.本质上升序列

我想到的是用回溯去找子集一个一个判断,当然这样的话会来的很慢,然后就在网上找到了大佬的方法,这东西居然是用动态规划来的,说是最长递增子序列的类似问题 ,感觉我好像写过类似的,但是去找了找居然没有,类似的是最长回文串,但是那玩意儿确实很不好理解

1.21动态规划(中等)-CSDN博客

最长回文串(回顾一下)

a和aa一定是,这样的话是a[i]==a[j]%%i-j<=1的情况,还有的话就是相差一定距离了,比如abcba,如果1-5是回文串,那么2-3一定是,不然就不满足回文串,所以在这样的条件下就可以写动态规划了

下面就分析这个题的解法,在别人的帖子里学习的·(蓝桥杯第十一届决赛)试题D:本质上升序列(动态规划)_蓝桥杯本质上升序列答案-CSDN博客

最长子序列问题

还有就是最长子序列的问题,给一串数字找到最长子序列,数据结构与算法之最长递增子序列-CSDN博客

流程大概就是遍历,找到比目前的数来的小,但是他的最长子序列又比目前的最长子序列来的要大,我们就更新,更新到要看的数据的前一个(比自己来的小但是有最长子序列的),更新完本身后再比较看看这个是不是最长的,如果是的话要更新总体最长的

#include <bits/stdc++.h>

using namespace std;

main()
{
	int a[9]={10,22,9,33,21,50,41,60,80};
	int n,i,j,cur,maxl=1;
	int* dp=(int*)calloc(n,sizeof(int));
	dp[0]=1;
	n=sizeof(a)/sizeof(a[0]);
	for(i=1;i<n;i++)
	{
		cur=0;
		for(j=0;j<i;j++)
		{
			if(a[i]>a[j])
			{
				if(dp[j]>cur)
				{
					cur=dp[j];
				}
			}
		}
		dp[i]=cur+1;
		if(dp[i]>maxl) maxl=dp[i];
	}
	cout<<maxl;
 } 
本题解法

回到本题,其实就是来看每一个字母的递增序列有多少,也就是说我们想做的不是找到最长子序列是有多长,而是从过程中入手,计算有几个递增子序列

在这个代码里遇到了几个常见的错误,首先就是memset函数,它只能初始化成0和-1,最开始想设置成1结果搞错了,第二就是i和j的顺序,要注意一下,这个题的解法很巧妙的地方在于如果是重复出现的,要剪掉重复的,其实就是剪掉它之前的递增子序列数,也就是f(j)

#include <bits/stdc++.h>

using namespace std;

main()
{
	string s;
	cin>>s;
	long long i,j,n,ans=0;
	n=s.size();
	cout<<n<<endl;
	long long dp[n];
	for(i=0;i<n;i++) dp[i]=1; 
	for(i=1;i<n;i++)
	{
		for(j=0;j<i;j++)
		{
			if(s[i]>s[j])
				dp[i]+=dp[j];
			else if(s[i]==s[j])
				dp[i]-=dp[j];
		}
	}
	for(i=0;i<n;i++)
	{
		cout<<dp[i]<<endl;
		ans+=dp[i];
	}
	cout<<ans;
 } 

2.排列距离

看着感觉很难,去查了一下发现这东西居然叫康托展开,原理是如果n个数字或者字符全排列,每个元素只出现一次,从小到大按字典排列好,从0开始给他们编号,从字符串映射到编号就是康托展开。

第十三届蓝桥杯 C/C++ 大学 A 组 排列距离 康托和逆康托展开_蓝桥杯排列距离-CSDN博客

由列全排可得到其次序编号(康托展开),由次序编号可以得到对应的第几个全排列(逆康托展开)。

【数论系列】 康托展开-CSDN博客

对于选择题来说就是可以直接手算了,给字母按顺序编号序号,之后计算一下然后减下来,但是要写代码的话就有点难了,应该是要一个visit数组,然后按照这个编号的顺序去遍历,本来想自己写,发现别人思路和我差不多,但是代码要来的漂亮很多,思路也很清晰

好奇该,感觉我得代码没啥问题,但是一直跑出来的结果奇奇怪怪的,和别人的也对不上,不过我输出了一下他的代码发现有负数,他那边kt函数用的是int,感觉像是溢出了,奇奇怪怪的

#include <bits/stdc++.h>

using namespace std;

long long f[18];

void fl(int n)
{
	f[0] = f[1] = 1; // 0的阶乘为1
    for(int i = 2; i <= n; i++) f[i] = f[i - 1] * i;
}

long long kt(string s)
{
	int i,j,tmp,n;
	long long ans=1;
	n=s.size();
	for(i=0;i<n;i++)
	{
		tmp=0;
		for(j=i+1;j<n;j++)
		{
			if(s[i]>s[j]) tmp++;
		}
		ans+=tmp*f[n-i-1];
	}
	return ans;
}

main()
{
	fl(18);
	string s1="aejcldbhpiogfqnkr",s2="ncfjboqiealhkrpgd";
	long long sum1,sum2,sum3,sum4;
	sum1=kt(s1);
	sum2=kt(s2);
	cout<<sum1<<" "<<sum2<<endl;
	sum3=sum2-sum1;
	sum4=f[17]-sum3;
	cout<<min(sum3,sum4); 
	

	
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值