【Pugnacious 模拟赛II】tech的密码

问题描述

寂静的星期三…………
   Nicole半夜去机房刷完题后,突然发现tech的U盘没有带走……
   果然,上面有“动物世界”“入党申请书”“毛主席选集”“金刚葫芦娃”“英语听力材料”“走进科学”等很可疑的压缩包,但是狡猾的tech都设了密码。
   历尽千辛万苦,Nicole发现一个文本文档,里面有很多数。
   确切的说,一共有N行,每一行有M个数字。这些数字都是1到M的一个排列。
   只是这些数全部都是有规律的,最后的密码肯定是这M列数字里面的某一列。而这一列的序号,是这N行数字的最长上升公共子序列的长度!!当然,你只需要告诉Nicole这个长度即可。

输入格式

第一行2个空格隔开的正整数N和M
   接下来N行,每行M个数,保证这M个数全部是1~M的一个排列。

输出格式

一个数,如题目所述。

样例输入

2 7
1 2 3 5 7 6 4
1 7 2 6 3 4 5

样例输出

4

提示

数据范围:
   对于100%的数据,有N<=100,M<=200
   
   说明:
   1 2 3 4和1 2 3 5均可。

解析:

• 抓住重点:

• 每个序列都是1到N的排列!

• 每个数在每个序列中只出现一次!

• 设定状态:f[x]表示以数字x结尾的最长上升公共子序列长度

• 状态转移:f[x] = f[y] + 1,其中1≤y≤x-1,且每个序列中y都在x左边

• 用pos[i][x]记录第i个序列中x的位置,则i=1,2,...,m时都要pos[i][y]<pos[i][x]

• 边界情况:如果找不到符合条件的y,则f[x]=1 • 最终答案:max(f[1],f[2],...,f[n])

• 时间复杂度𝑂 (n2m)

• 判断y能否转移到x,需要𝑂(m) 的时间,整个DP需要判断𝑂 (n*n) 次

代码:

#include <bits/stdc++.h>
using namespace std;
int p[1005][1005],n,m,f[1000];
int a[3000],b[3000],x,k;
int ans;
int main() {
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			cin>>x;
			p[i][x]=j;
		}
	}
	for(int i=1; i<=m; i++) {
		f[i]=1;
		for(int j=i-1; j>=1; j--) {
			if(f[i]<=f[j]) {
				bool fg=1;
				for( k=1; k<=n; k++) {
					if(p[k][j]>p[k][i]) {
						fg=0;
					}
				}
				if(fg==1) {
					f[i]=f[j]+1;
				}
			}
		}
		ans=max(ans,f[i]);
	}
	cout<<ans<<endl;
}

稍后会完善思路 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值