• 【ARC068F】Solitaire


    Description

      
    ​   你有一个双端队列和 (N) 个数字,先按 (1)(N) 的顺序每次从任意一端插入当前数字,再进行 (N) 次操作每次可以从两端弹出,求有多少种弹出序列满足第 (K) 位为 (1)
      
      ​ (N le 2000)
      
        
      

    Solution

      
    ​   考虑双端队列的样子,插入完成后,元素大小形象来看一定是一个"V"的形状,并且最低端是1。
      
    ​   再考虑符合要求的、合法的弹出序列的性质:
      
    ​   (1)首先第(K)个必须是1。
      
    ​   (2)前(K-1)个数,一定是两个或一个单调减的队列混合而成的。
      
    ​   (3)后(N-K)个数,其最大值应小于某一个(2)提到的单调队列的最小值。
      
    ​   一旦前(K-1)个数固定,最后剩下的就是一个单调的队列,取出方式有(2^{N-K-1})种。
      
    ​   所以接下来要算出合法序列的前(K-1)个数有多少种情况。
      
    ​   设(f_{i,j})表示已经确定了前(1...i)个数,且确定的数中最小值为(j),有多少种方案。
      
    ​   考虑从(f_{i,j})转移到(f_{i+1})(f_{i,j})代表着若干种符合(j)这个特征的长度为(i)的数列,不论这些数列的两个(或者一个)单调队列是怎么构成的,我们只需要看看它们能够在第(i+1)位填上什么数合法转移就好。
      
    ​   首先,下一位填(1...j-1)都是可行的。由于当前序列是合法序列,也就是说满足(3)。可以这样拆分出两个队列,使得一个队列的最小值是(j),而另一个队列专门用来满足(3)。那么将新的数接在前面那个队列后面,仍然是合法序列。所以有(f_{i,j} ightarrow f_{i+1,k};;;k<j)
      
    ​   其次,如果要填大于(j)的数呢?只能填没出现过的、最大的那个数。例如(n=7),当前序列是7 6 3 2,只能填入5。如果填的是其他数如4,你会发现,4一定要是某一个队列的结尾,由于它不是未出现的数的最大的数,这意味着后(N-K)个数的数列有比它更大的,那么这个队列不满足(3)。考虑另一个队列能否满足,事实上是不可能的,因为最小值一定要是另一个队列的结尾(不然就不止2个队列了),它也不满足(3)。
      
    ​   所以有(f_{i,j} ightarrow f_{i+1,j})。这个转移有点神秘,它没有体现出任何(j)的变化,但它的确能表示,因为这一步转移相当于对每一个确切方案填了唯一确定的一个数,所以可以直接转移去对应特征的状态,也就是最小值仍然是(j)
      
    ​   注意边界,那些(j>n-i+1)(f_{i,j})是不合法的,那些(j=n-i+1)的状态不可以用于第二类转移,因为没有空余的数可以填。
        
    ​   第一个转移用后缀和优化,复杂度是(mathcal O(n^2))
      
    ​  
      

    Code

      

    #include <cstdio>
    using namespace std;
    const int N=2005,MOD=1e9+7;
    int n,m;
    int f[N];
    void readData(){
    	scanf("%d%d",&n,&m);
    }
    void dp(){
    	f[n+1]=1;
    	int sum,last;
    	for(int i=1;i<m;i++){
    		sum=f[n-i+2];
    		for(int j=n-i+1;j>=2;j--){
    			(sum+=f[j])%=MOD;
    			if(j<=n-i+1)
    				f[j]=sum;
    		}
    	}
    	int ans=0;
    	for(int j=2;j<=n-(m-1)+1;j++) (ans+=f[j])%=MOD;
    	if(m==1) ans=1;
    	for(int i=1;i<=n-m-1;i++) (ans<<=1)%=MOD;
    	printf("%d
    ",ans);
    }
    int main(){
    	readData();
    	dp();
    	return 0;
    }
    

  • 相关阅读:
    OCP-1Z0-052-V9.02-177题
    游戏服务端IOCP模型,自己封装的一个类,3行代码搞定服务端。
    OCP-1Z0-052-V9.02-116题
    OCP-1Z0-052-V9.02-72题
    map按value值查找——find_if的使用
    Oracle OCP 11G 052答案解析目录
    Oracle OCP 11G 052 V8.02与V9.02版本对比
    OCP-1Z0-052-V8.02-102题
    OCP-1Z0-052-V8.02-117题
    在完成端口IOCP模型判断客户端是否已关闭连接(掉线)
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9444063.html
Copyright © 2020-2023  润新知