zoukankan      html  css  js  c++  java
  • 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);
    }

  • 相关阅读:
    C# .Net基础知识点解答
    依赖注入框架Autofac的简单使用
    Linq表达式、Lambda表达式你更喜欢哪个?
    C#抽象类、接口、虚函数和抽象函数
    MVC面试问题与答案
    并发 并行 同步 异步 多线程的区别
    .Net中的控制翻转和依赖注入
    解析ASP.NET WebForm和Mvc开发的区别
    测试与代码质量
    netty 同步调用
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477111.html
Copyright © 2011-2022 走看看