zoukankan      html  css  js  c++  java
  • [JXOI2017]数列

    题目

    一个不太一样的做法

    (A_{i-1}=x),称(A_1)(A_{i-2})中大于等于(A_{i-1})的最小值(R)为上界,(A_1)(A_{i-2})中小于等于(A_{i-1})的最大值(L)为下界。对于一组((L,R,x))显然有(Lleq xleq R),我们下一个能填的数也只能在这个范围内。

    当我们(A_i=y)的时候,考虑新的上下界分别是谁。

    (xleq yleq R)的时候,显然小于等于(y)中最大的是(x),大于等于(y)中最大的是(R),所以新的下界是(x),上界(R),三元组变成了((x,R,y))

    (Lleq y< x)的时候,新的上界是(x),下界是(L),三元组变成了((L,x,y))

    到这里我们就可以写一个dp了,设(f_{i,j,k,p})表示填了(i)个数,末尾三元组的状态是((j,k,p)),转移的时候枚举下一位填什么推出下一个三元组即可。状态数是(O(nr_i^3)),转移是(O(r_i))的,复杂度是(O(nr_i^4))不是很能接受

    再观察一下这个dp的转移,发现它非常别致,我们枚举下一位填的数(y)

    (pleq yleq k)(f_{i,j,k,p})(f_{i+1,x,k,y})转移,这个转移和(j)这一维没有关系

    (jleq y< p)(f_{i,j,k,p})(f_{i+1,j,x,y})转移,这个转移和(k)这一维没有关系

    考虑一下是否可以去掉一维,上下界中只保存一个能否进行转移

    显然是可以的,设(dp_{i,j,k})表示当前填了(i)个数,上/下界为(j),末尾填的数为(k)。我们强行规定当(kleq j)的时候,(j)为上界;当(k>j)的时候,(j)为下界
    即对于原来的(f_{i,j,k,p})拆分成了两个状态(dp_{i,j,p})(dp_{i,k,p}),这两个状态各自完成(f_{i,j,k,p})的一部分转移。其中(dp_{i,j,p})负责(jleq y<p)的转移;(dp_{i,k,p})负责(pleq yleq k)的转移。注意转移之后得到的仍旧是一个完整的上下界都有的状态,我们还是要把这个状态拆分一下

    转移的时候还是枚举下一位填什么数,根据填的数推出转移的状态即可。注意当一下位填的数和上下界相等时,新的上下界就固定了。

    这样的状态数就变成了(O(nr_i^2)),复杂度是(O(nr_i^3)),不知道为什么跑的比较快,luogu最优解,loj位列rk3

    代码

    #include<bits/stdc++.h>
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int maxn=155;
    const int mod=998244353;
    inline int qm(int x) {return x>=mod?x-mod:x;}
    int h[55],n,o,R,dp[2][maxn][maxn];
    int main() {
    	n=read();for(re int i=1;i<=n;i++) h[i]=read(),R=max(R,h[i]);R++;
    	for(re int i=1;i<=h[2];++i) 
    		for(re int j=1;j<=h[1];++j) {
    			if(j>=i) {if(i!=j) dp[0][i][0]++;}
    			else dp[0][i][R]++;
    			dp[0][i][j]++;
    		}
    	for(re int i=3;i<=n;i++,o^=1) {
    		memset(dp[o^1],0,sizeof(dp[o^1]));
    		for(re int j=1;j<=h[i-1];j++)
    			for(re int k=0;k<=R;++k) {
    				if(!dp[o][j][k]) continue;
    				if(k<j) {
    					for(re int p=k;p<j;p++)
    					if(p<=h[i]&&p>0) {
    						if(p==k) {
    							dp[o^1][p][p]=qm(dp[o^1][p][p]+dp[o][j][k]);
    							continue;
    						}
    						dp[o^1][p][k]=qm(dp[o^1][p][k]+dp[o][j][k]);
    						dp[o^1][p][j]=qm(dp[o^1][p][j]+dp[o][j][k]);
    					}
    				}
    				else {
    					for(re int p=j;p<=k;++p)
    					if(p<=h[i]&&p>0) {
    						if(p==j||p==k) {
    							dp[o^1][p][p]=qm(dp[o^1][p][p]+dp[o][j][k]);
    							continue;
    						}
    						dp[o^1][p][j]=qm(dp[o^1][p][j]+dp[o][j][k]);
    						dp[o^1][p][k]=qm(dp[o^1][p][k]+dp[o][j][k]);
    					}
    				}
    			}
    	}
    	int ans=0;
    	for(re int i=1;i<=h[n];++i)
    		for(re int j=i;j<=R;++j) ans=qm(ans+dp[o][i][j]);
    	return !printf("%d
    ",ans);
    }
    
  • 相关阅读:
    谷粒商城学习——P41vue组件化
    谷粒商城学习——P40计算属性、侦听器、过滤器
    谷粒商城学习——P38-39Vue-指令-单向绑定&双向绑定&v-onv-forv-if
    谷粒商城学习——P37vue基本语法——双向绑定、事件处理
    谷粒商城学习——P36Vue介绍与HelloWord
    谷粒商城学习——P35模块化
    谷粒商城学习——P34Promise异步编排
    Windows tcp/ip(CVE-2020-16898)远程代码执行蓝屏漏洞复现
    QQ群关系可视化3D查询搭建
    Skywalking 8.1 Docker 服务端部署
  • 原文地址:https://www.cnblogs.com/asuldb/p/11658200.html
Copyright © 2011-2022 走看看