zoukankan      html  css  js  c++  java
  • Jzoj5235 好的排列

    对于一个1->n的排列 ,定义A中的一个位置i是好的,当且仅当Ai-1>Ai 或者Ai+1>Ai。对于一个排列A,假如有不少于k个位置是好的,那么称A是一个好的排列。

    现在有q个询问,每个询问给定n,k,问有多少排列是好的。答案对10^9+7取模。

    显然是计数类dp,我们设f[i][j]表示对于一个1->i的排列,好的位置有j个的情况

    考虑转移,显然f[i][j]->f[i+1][k]相当于插入一个i+1

    那么我们考虑对j的影响,显然f[i][j]只能转移到f[i+1][j]或者f[i][j],因为这取决于你将i+1放在哪个位置上

    如果放在一个不是好位置的两边,那么j就会+1,否则j不变,而且显然,不好的位置一定不连续(显然)

    那么转移就十分简单了,参考code

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define M 1000000007
    #define L long long
    using namespace std;
    void ad(int& x,L y){ x=(y+x)%M; }
    int f[3010][3010]={0},s[3010][3010]={0},n;
    int main(){
    	freopen("permutation.in","r",stdin);
    	freopen("permutation.out","w",stdout);
    	f[1][0]=1; f[2][1]=2; 
    	f[3][1]=2; f[3][2]=4;
    	for(int i=3;i<3000;++i){
    		L pi=(i+1)-2,pj=2;
    		for(int j=i-1;pi>=0;--j){
    			ad(f[i+1][j],f[i][j]*pi);
    			ad(f[i+1][j+1],f[i][j]*pj);
    			pi-=2; pj+=2;
    		}
    	}
    	for(int i=1;i<=3000;++i)
    		for(int j=i-1;~j;--j){
    			s[i][j]=s[i][j+1];
    			ad(s[i][j],f[i][j]);
    		}
    	scanf("%d",&n);
    	for(int x,y,i=0;i<n;++i){
    		scanf("%d%d",&x,&y);
    		printf("%d
    ",s[x][y]);
    	}
    }

  • 相关阅读:
    UVa 1394 约瑟夫问题的变形
    UVa 572 油田(DFS求连通块)
    UVa 699 下落的树叶
    Prim求解最小生成树
    UVa 839 天平
    UVa 11988 破损的键盘(链表)
    UVa 442 矩阵链乘(栈)
    UVa 二叉树的编号(二叉树)
    UVa 12100打印队列(队列)
    约瑟夫圆桌问题
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/7846019.html
Copyright © 2011-2022 走看看