Zoltan

link

先说我并没有完全搞懂这道题,我只能写一下我从这道题中学到了什么。

题面有错,严重的错误。原题目说的是一个数只能被放在之前所有数的最前面或者所有数的最后面,毕竟考虑到在两个数之间再写下新的数始终是困难的。后面统计答案的部分不管,我并没有完全理解,但前面计算LIS的部分提供了一个重要思想。对于任意的一个数来说,假如它出现在最后的LIS中,它要么是在第一个数前面,要么在后面(这不是废话吗),既然如此,我们可以把它克隆一下在前面和后面对应位置各放一个,然后对于这个加长版的序列跑一次LIS即可因为每个新序列的方案都是可以对应出一种合法的加数方案的(当然可以这么搞的前提是题目中要求的是严格,如果不严格就不能保证一个数只被选一次),求就可以了。

另外后面提供了一种关于LIS计数的方法,考虑在树状数组每个节点上加上一个维度,这个维度记录了这个节点对应的长度的数量。更新的时候如果其中一个对应的长度长,那么直接覆盖即可,否则把二者的方案数加起来就可以啦。

#include<bits/stdc++.h>
//#define feyn
#define int long long
const int N=200010;
const int mod=1e9+7;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

int m,a[N],b[N],e2[N];

#define lowbit (wh&-wh)
struct node{int len,an;}t[N],newone;
inline node operator +(node s1,node s2){
	if(s1.len==s2.len)return s1.an=(s1.an+s2.an)%mod,s1;
	else return s1.len>s2.len?s1:s2;
}
inline void change(int wh,node data){
	for(;wh<=m;wh+=lowbit)t[wh]=t[wh]+data;
}
inline node work(int wh){
	node an=(node){0,0};
	for(;wh;wh-=lowbit)an=an+t[wh];
	if((++an.len)==1)an.an=1;
	return an;
}
#undef lowbit

int len[N],cnt[N];

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);e2[0]=1;
	for(int i=1;i<=m;i++)e2[i]=e2[i-1]*2%mod;
	for(int i=1;i<=m;i++)read(a[i]),b[i]=a[i];
	sort(b+1,b+m+1);
	int n=unique(b+1,b+m+1)-b-1;
	for(int i=1;i<=m;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
	int ans_len=0,ans=0;
	for(int i=m;i;i--){
		node now=work(a[i]-1);
		ans_len=max(ans_len,now.len);
		change(a[i],now);
	}
	for(int i=2;i<=m;i++){
		node now=work(a[i]-1);
		ans_len=max(ans_len,now.len);
		change(a[i],now);
	}
	for(int i=1;i<=m;i++)t[i]=newone;
	for(int i=m;i;i--){
		node now=work(a[i]-1);
		len[i]=now.len,cnt[i]=now.an;
		change(a[i],now);
	}
	for(int i=1;i<=m;i++)t[i]=newone,a[i]=n+1-a[i];
	for(int i=m;i;i--){
		node now=work(a[i]-1);
		if(now.len+len[i]==ans_len+1){
			ans+=now.an*cnt[i]%mod*e2[m-ans_len];ans%=mod;
		}
		change(a[i],now);
	}
	printf("%lld %lld\n",ans_len,ans);
	
	return 0;
}
posted @ 2022-07-31 17:37  Feyn618  阅读(69)  评论(0编辑  收藏  举报