zoukankan      html  css  js  c++  java
  • 洛谷 P4484

    洛谷题面传送门

    首先看到 LIS 我们可以想到它的 (infty) 种求法(bushi),但是对于此题而言,既然题目出这样一个数据范围,硬要暴搜过去也不太现实,因此我们需想到用某种奇奇怪怪的方式进行状态压缩 DP,这样一来就可以排除掉不少常用的求 DP 的方法:譬如最常用的从左往右顺着钦定元素并设 (f_i) 表示以 (i) 结尾的 LIS 的长度的方法,因此考虑换个角度,从小到大添加元素。还是设 (f_i) 表示以 (i) 结尾的 LIS 的长度,那么考虑在一轮中,我们在 (i)(i+1) 这两个位置中间插入一个比当前所有数都大的数会对 (f) 产生怎样的影响,有:

    • (f_{i+1}=1+maxlimits_{j=1}^if_j)
    • 对于 (j>i),有新的 (f_{j+1}) 等于 (f_j)

    注意到这里涉及前缀 (max),因此设 (mf_i=maxlimits_{j=1}^if_j),又注意到相邻两个 (mf_i) 的差最多为 (1),因此考虑 (mf_i)差分序列 (d_i=mf_i-mf_{i-1}),根据之前的推论显然它是一个 (01) 序列,这样就天然地形成了状压 (dp) 的模型。由于我们的 (dp) 都建立在差分序列的基础上,因此我们再来探究下加入一个比当前所有数都大的数会对差分序列产生怎样的影响:

    • (d_{i+1}=1)
    • 对于所有 (jge i+1),有新的 (d_{j+1}) 等于原来的 (d_j)
    • 进行以上两个操作之后,我们找到 (i+1) 后面第一个 (d_j=1)(j)——如果不存在这样的 (j) 则跳过这一步,并令 (d_j=0)

    这样我们就可以设 (dp_{i,j}) 表示当前插入了 (1sim i)(d) 的状态为 (j) 的方案数,转移就枚举在哪里插入 (i+1),然后二进制模拟 (d) 的变化即可。注意到 (j) 只用枚举到 (2^i),因此 ((i,j)) 的总枚举量是 (2^n) 的,再加上转移的 (n),总复杂度 (2^n·n),注意滚动数组优化空间,否则会获得 MLE 0 的好成绩。

    void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
    int qpow(int x,int e){
    	int ret=1;
    	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
    	return ret;
    }
    int n,dp[2][134217733];
    int main(){
    	scanf("%d",&n);
    	dp[1][1>>1]=1;int nxt=0,cur=1;
    	for(int i=1;i<n;i++){
    		for(int j=0;j<(1<<i+1);j++) dp[nxt][j>>1]=0;
    		for(int j=1;j<(1<<i);j+=2) if(dp[cur][j>>1]){
    //			printf("%d %d %d
    ",i,j,dp[cur][j]);
    			for(int k=0;k<=i;k++){
    				int nmsk=0;
    				if(k) nmsk=j&((1<<k)-1);
    				nmsk|=(1<<k);
    				int rst=((1<<i)-1)^((!k)?0:((1<<k)-1));
    				nmsk|=(j&rst)<<1;
    				if((j&rst)){int S=j&rst;nmsk^=(S&(-S))<<1;}
    				add(dp[nxt][nmsk>>1],dp[cur][j>>1]);
    			}
    		} swap(cur,nxt);
    	} int res=0,fac=1;
    	for(int i=1;i<(1<<n);i+=2) res=(res+1ll*__builtin_popcount(i)*dp[cur][i>>1])%MOD;
    	for(int i=1;i<=n;i++) fac=1ll*fac*i%MOD;
    	res=1ll*res*qpow(fac,MOD-2)%MOD;
    	printf("%d
    ",res);
    	return 0;
    }
    

    直接按照上面的做法写大约会 TLE 3~6 个点,取决于你的实现,不过注意到这题长得一脸打表的样子,于是你对 (n) 比较大的情况在本地跑一下上面的代码,算出答案特判下即可通过此题。

    并没有看懂楼下 EI 神仙的题解

    void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
    int qpow(int x,int e){
    	int ret=1;
    	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
    	return ret;
    }
    int n,dp[2][134217733];
    int main(){
    	scanf("%d",&n);
    	if(n==22) return puts("749077581"),0;
    	if(n==23) return puts("301075008"),0;
    	if(n==24) return puts("314644758"),0;
    	if(n==25) return puts("102117126"),0;
    	if(n==26) return puts("819818153"),0;
    	if(n==27) return puts("273498600"),0;
    	if(n==28) return puts("267588741"),0;
    	dp[1][1>>1]=1;int nxt=0,cur=1;
    	for(int i=1;i<n;i++){
    		for(int j=0;j<(1<<i+1);j++) dp[nxt][j>>1]=0;
    		for(int j=1;j<(1<<i);j+=2) if(dp[cur][j>>1]){
    //			printf("%d %d %d
    ",i,j,dp[cur][j]);
    			for(int k=0;k<=i;k++){
    				int nmsk=0;
    				if(k) nmsk=j&((1<<k)-1);
    				nmsk|=(1<<k);
    				int rst=((1<<i)-1)^((!k)?0:((1<<k)-1));
    				nmsk|=(j&rst)<<1;
    				if((j&rst)){int S=j&rst;nmsk^=(S&(-S))<<1;}
    				add(dp[nxt][nmsk>>1],dp[cur][j>>1]);
    			}
    		} swap(cur,nxt);
    	} int res=0,fac=1;
    	for(int i=1;i<(1<<n);i+=2) res=(res+1ll*__builtin_popcount(i)*dp[cur][i>>1])%MOD;
    	for(int i=1;i<=n;i++) fac=1ll*fac*i%MOD;
    	res=1ll*res*qpow(fac,MOD-2)%MOD;
    	printf("%d
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    pom配置进行版本号统一管理
    设置配置文件信息时的classpath
    [spring]启动时报错:NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I
    powerdesigner使用之——从“概念模型”到“物理模型”
    Spring-MVC理解之二:前置控制器
    Spring-MVC理解之一:应用上下文webApplicationContext
    spring配置:context:property-placeholder 读取配置文件信息 在配置文件中使用el表达式填充值
    javaee web项目的目录结构
    22 Swap Nodes in Pairs
    21. Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/ET2006/p/luogu-P4484.html
Copyright © 2011-2022 走看看