• Jzoj5600 Arg


    给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS.

    dp套dp好题!

    我们先要考虑怎么搞一个状态出来

    考虑做lis的两种方法:

    1.设f[i]表示做到i的最长子序列长度

    2.设f[i]表示长度为i的上升子序列最后那个数最小是多少

    第一种方式不好设状态,我们考虑第二种

    显然,如果知道f里有哪些数字,就可以还原f

    那么我们设一个状态f[S][F]表示现在原来的序列中已经用了S这些数字,f数组中的数为F的方案数

    考虑转移,显然有2种方式:
    1.向S中添加一个不在A中的元素,这种情况直接转就可以了

    2.向S中添加一个在A中的元素,这个时候要考虑顺序,如果A[1..j]都在F中出现过,那么我们可以添加的元素就是A[j+1]

    最后答案就是∑ f[S][F] 其中S为全集,F的集合大小为A的长度

    这样不能满分,考虑简化状态,由于F∈ S,所以这个状态可以用3进制表示,这样就可以通过了

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int d3[20]={1},ans=0;
    int n,m,v[20],g[20],p[20],s[20],f[20000000];
    inline void cal(int i,int& j,int& k){
    	for(j=k=0;i;i/=3){
    		if(i%3==1) ++j; else
    		if(i%3==2) ++k;
    	}
    }
    int main(){
    	freopen("arg.in","r",stdin);
    	freopen("arg.out","w",stdout);
    	scanf("%d%d",&n,&m); *f=1;
    	for(int i=0;i<m;++i) scanf("%d",v+i),p[--v[i]]=i+1;
    	for(int i=1;i<=n;++i) d3[i]=d3[i-1]*3;
    	for(int i=0,k;i<d3[n];++i) if(f[i]){
    		for(int j=*g=k=0;j<n;++j){
    			s[j]=(i/d3[j])%3;
    			if(s[j]==1) g[++*g]=j;
    			if(s[j]) k=max(k,p[j]);
    		}
    		for(int j=0,t=1;j<n;++j) if(!s[j]){
    			while(j>g[t] && t<=*g) ++t;
    			if(p[j] && p[j]!=k+1) continue;
    			if(t<=*g) f[i+d3[j]+d3[g[t]]]+=f[i];
    			else f[i+d3[j]]+=f[i];
    		}
    	}
    	for(int i=0,j,k;i<d3[n];++i){
    		cal(i,j,k);
    		if(j==m && j+k==n){
    			ans+=f[i]; end:;
    		}
    	}
    	printf("%d
    ",ans);
    }

  • 相关阅读:
    Java_static
    Java_字符串操作
    Java_==
    Java_字符串
    Java_Random
    Java_Scanner
    杨辉三角
    颜色分类
    字符串倒序
    jQuery的基本事件
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477111.html
Copyright © 2020-2023  润新知