zoukankan      html  css  js  c++  java
  • ●观光(17.12.02多校联测题目)

    题目:

    e0b8be2d624e0993a5d561b81eab1eb7

    题解:

    DP,方案数统计,(神奇)。

    题意不再赘述。
    但不得不说,做这种dp真的好难受啊。

    我们做如下考虑:
    首先,起点只有出度,终点只有入度,其它点的出入度均为 1(这个结论好像没啥明显的用处哈)。

    如果把 K位置作为终点,那么序列被分为了两段 :[1,K-1] 和 [k+1,N]
    那么如何把左右两边"有机地"和终点结合起来呢?
    假设,
    在左边按照某种方式,用到所有点,连接出了 X 条终点方向指向 K(即指向右边)的链。
    在右边按照某种方式,用到所有点,连接出了 Y 条终点方向指向 K(即指向左边)的链。

    然后按照一条左边的链,一条右边的链的方式(即交替),最后连上终点 K的方案数为
    = X! * Y!
    另外,要想能够交替成功,X和 Y的差值不能超过 1
     
    所以由上面的这个东西得到启发,我们只需要维护出
    L[K-1][j] 表示 用到[1,K-1]的区间里的所有点,连接出 j条终点方向指向 K(即指向右边)的链 的方案数。
    R[K+1][j] 表示 用到[K+1,N]的区间里的所有点,连接出 j条终点方向指向 K(即指向左边)的链 的方案数。
    那么 就可以得出 K为终点时的方案数了。
    ans[K]=sigma { L[K-1][j]*R[K+1][j+1] * j! * (j+1)!
                           +L[K-1][j+1]*R[K+1][j] * (j+1)! * j!
                            +2*L[K-1][j]*R[K+1][j] * j! *j! } (0<=j<=N)

    接下来便是要 DP求出 L[i][j],R[i][j]数组。
    以左边为例,先枚举 i(代表用到 [1,i]里的所有点),再枚举 j(表示连接出 j条链)
    如果 S[i]=='<',那么有如下转移:
        L[i][j]+=(j+1)*j*L[i-1][j+1]     用'<'合并两条链(把'<'放在新形成的链中间)
       L[i][j]+=L[i][j]+j*L[i-1][j]        把'<'接在已有的链首
    如果 S[i]=='>',那么。。。
        L[i][j]+=L[i-1][j-1]                 由'>'产生新的链尾(即产生一条新的链)
        L[i][j]+=j*L[i-1][j]                  把'>'接在已有的链尾

    右边 R的处理大同小异,反着来就好了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 1005
    #define _ %mod
    using namespace std;
    const int mod=1000000007;
    char S[MAXN];
    int L[MAXN][MAXN],R[MAXN][MAXN],fac[MAXN];
    int N;
    int main()
    {
    	scanf("%d",&N); scanf("%s",S+1);
    	if(N==1) {printf("1"); return 0;} fac[0]=1; 
    	for(int i=1;i<=N;i++) fac[i]=1ll*i*fac[i-1]_;
    	L[0][0]=1; R[N+1][0]=1;
    	for(int i=1;i<=N;i++)//处理左侧 
    		for(int j=1;j<=N;j++){
    			if(S[i]=='<')	
    				L[i][j]=(1ll*L[i][j]+1ll*(j+1)*j*L[i-1][j+1])_,//用'<'合并两条链(把'<'放在链中间)
    				L[i][j]=(1ll*L[i][j]+1ll*j*L[i-1][j])_;//把'<'接在链首
    			else
    				L[i][j]=(1ll*L[i][j]+1ll*L[i-1][j-1])_,//由'>'产生新的链尾
    				L[i][j]=(1ll*L[i][j]+1ll*j*L[i-1][j])_;//把'>'接在链尾 
    		}
    	for(int i=N;i>=1;i--)//处理右侧 
    		for(int j=1;j<=N;j++){
    			if(S[i]=='>')
    				R[i][j]=(1ll*R[i][j]+1ll*(j+1)*j*R[i+1][j+1])_,//用'>'合并两条链(把'<'放在链中间)
    				R[i][j]=(1ll*R[i][j]+1ll*j*R[i+1][j])_;//把'>'接在链首
    			else
    				R[i][j]=(1ll*R[i][j]+1ll*R[i+1][j-1])_,//由'<'产生新的链尾
    				R[i][j]=(1ll*R[i][j]+1ll*j*R[i+1][j])_;//把'<'接在链尾
    		}
    	for(int k=1,ans;k<=N;k++){//计算以 K为终点时的方案数 
    		ans=0;
    		for(int j=0;j<=N;j++)
    			ans=(1ll*ans+1ll*L[k-1][j]_*fac[j]_*R[k+1][j+1]_*fac[j+1]_)_,
    			ans=(1ll*ans+1ll*L[k-1][j+1]_*fac[j+1]_*R[k+1][j]_*fac[j]_)_,
    			ans=(1ll*ans+2ll*L[k-1][j]_*fac[j]_*R[k+1][j]_*fac[j]_)_;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/zj75211/p/7954465.html
Copyright © 2011-2022 走看看