zoukankan      html  css  js  c++  java
  • 洛谷 P3205 [HNOI2010]合唱队

    题目传送门


    思路:

    对于理想队形中[l, r]的部分,它可以由第l个人从左边入队,也可以由第r个人从右边入队。

    对于第l个人从左边入队的情况,可分为两种:上一个是第l+1个人从左端入队,则需满足h[l] < h[l+1];上一个是第r个人从右端入队,则需满足h[l] < h[r]。

    对于第r个人从右边入队的情况则同理。

    那么我们可以设f[i][j][k]表示从i到j的方案数,当k=0时,表示上一个入队的是第i个人,当k=1时,表示上一个入队的是第j个人。

    根据上面的分析不难写出转移方程:

    if(h[i] < h[i+1]) f[i][j][0] += f[i+1][j][0];
    if(h[i] < h[j]) f[i][j][0] += f[i+1][j][1];
    if(h[i] < h[j]) f[i][j][1] += f[i][j-1][0];
    if(h[j] > h[j-1]) f[i][j][1] += f[i][j-1][1];
    

    为了避免重复计算,所以预处理中我们只将所有的f[i][i][0]置为1即可。


    Code:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    //Mystery_Sky
    //
    #define M 10000100
    #define INF 0x3f3f3f3f
    #define ll long long
    #define Mod 19650827
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    int n;
    int f[1001][1001][2], h[1001];
    int main() {
    	n = read();
    	for(int i = 1; i <= n; i++) h[i] = read(), f[i][i][0] = 1;
    	for(int len = 1; len <= n; len++) {
    		for(int i = 1; i + len - 1 <= n; i++) {
    			int j = i + len - 1;
    			if(h[i] < h[i+1]) f[i][j][0] += f[i+1][j][0];
    			if(h[i] < h[j]) f[i][j][0] += f[i+1][j][1];
    			if(h[i] < h[j]) f[i][j][1] += f[i][j-1][0];
    			if(h[j] > h[j-1]) f[i][j][1] += f[i][j-1][1];
    			f[i][j][0] %= Mod, f[i][j][1] %= Mod;
      		}
    	}
    	printf("%d
    ", (f[1][n][0] + f[1][n][1]) % Mod);
    	return 0;
    } 
    
  • 相关阅读:
    【Jsoi2010】连通数
    【CQOI2009】中位数图
    【POJ 1151】 Altlantis
    【2017省中集训】 香港记者
    【AHOI2009】中国象棋
    【SCOI 2009】 Windy数
    【HDU 4722】 Good Numbers
    【HDU 2089】 不要62
    BZOJ3129 SDOI2013方程(容斥原理+扩展lucas)
    BZOJ1042 HAOI2008硬币购物(任意模数NTT+多项式求逆+生成函数/容斥原理+动态规划)
  • 原文地址:https://www.cnblogs.com/Benjamin-cpp/p/11443445.html
Copyright © 2011-2022 走看看