hdu6635 Nonsense time(2019多校第六场1001)

【题目描述】

传送带
给定某个n的排列,给定其中数字可见的顺序(在原序列的位置不变,仅改变是否可见的属性),求每个状态的LIS

【思路】

题目特地说了这个排列是随机生成的,其实是因为随机序列LIS的期望长度是n1/2 反向思考,看成是对原序列进行删除操作,每找一次LIS时间复杂度是nlgn,而由于期望长度是根号n,所以当前删除最长子序列的概率是1/根号n,n次删除操作,所以总的时间复杂度是n根号nlgn

知乎上有一个回答很严谨地讨论了关于随机序列LIS期望长度的解决方法
传送带

【代码】

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int MAXN=5e4+10;
const int MAXM=2e3+10;
const ll P=1e9+7;
const double eps=1e-10;
const double pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f;
int T;
int n;
int cnt;
int dp[MAXN];
int vis[MAXN];
int tag[MAXN];
int a[MAXN];
int x[MAXN];
int ans[MAXN];
vector f;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(tag,0,sizeof(tag));
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		f.clear();
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			int pos=lower_bound(f.begin(),f.end(),a[i])-f.begin();
			if(pos>=f.size()) f.push_back(a[i]);
			f[pos]=a[i];
			dp[i]=pos;
		}
		cnt=f.size()-1;
		for(int i=n;i>=1&&cnt>=0;i--) 
			if(dp[i]==cnt) vis[a[i]]=1,cnt--;
		for(int i=1;i<=n;i++) scanf("%d",&x[i]);
		for(int i=n;i>=1;i--){
			ans[i]=f.size();
			tag[x[i]]=1;
			if(vis[a[x[i]]]==1){
				f.clear();
				memset(vis,0,sizeof(vis));
				for(int j=1;j<=n;j++){
					if(tag[j]) {dp[j]=-1;continue;}
					int pos=lower_bound(f.begin(),f.end(),a[j])-f.begin();
					if(pos>=f.size()) f.push_back(a[j]);
					f[pos]=a[j];
					dp[j]=pos;
				}
				cnt=f.size()-1;
				for(int i=n;i>=1&&cnt>=0;i--) 
					if(dp[i]==cnt) vis[a[i]]=1,cnt--;
			}
		}
		for(int i=1;i

你可能感兴趣的:(LIS,hdu)