• 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]);
    	}
    }

  • 相关阅读:
    区间DP入门
    Prime Permutation(思维好题 )
    小字辈 (bfs好题)
    博弈论小结之尼姆博弈
    Hometask
    Lucky Sum (dfs打表)
    对称博弈
    尼姆博弈
    莫队算法 ( MO's algorithm )
    Codeforces 988D Points and Powers of Two ( 思维 || 二的幂特点 )
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477204.html
Copyright © 2020-2023  润新知