zoukankan      html  css  js  c++  java
  • BZOJ1925 [Sdoi2010]地精部落 【dp】

    题目

    传说很久以前,大地上居住着一种神秘的生物:地精。 地精喜欢住在连绵不绝的山脉中。具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到N 之间的正 整数。 如果一段山脉比所有与它相邻的山脉都高,则这段山脉是一个山峰。位于边 缘的山脉只有一段相邻的山脉,其他都有两段(即左边和右边)。 类似地,如果一段山脉比所有它相邻的山脉都低,则这段山脉是一个山谷。 地精们有一个共同的爱好——饮酒,酒馆可以设立在山谷之中。地精的酒馆 不论白天黑夜总是人声鼎沸,地精美酒的香味可以飘到方圆数里的地方。 地精还是一种非常警觉的生物,他们在每座山峰上都可以设立瞭望台,并轮 流担当瞭望工作,以确保在第一时间得知外敌的入侵。 地精们希望这N 段山脉每段都可以修建瞭望台或酒馆的其中之一,只有满足 这个条件的整座山脉才可能有地精居住。 现在你希望知道,长度为N 的可能有地精居住的山脉有多少种。两座山脉A 和B不同当且仅当存在一个 i,使得 Ai≠Bi。由于这个数目可能很大,你只对它 除以P的余数感兴趣。

    输入格式

    仅含一行,两个正整数 N, P。

    输出格式

    仅含一行,一个非负整数,表示你所求的答案对P取余 之后的结果。

    输入样例

    4 7

    输出样例

    3

    提示


    对于 20%的数据,满足 N≤10;
    对于 40%的数据,满足 N≤18;
    对于 70%的数据,满足 N≤550;
    对于 100%的数据,满足 3≤N≤4200,P≤109

    题解

    小程序,大思维
    这是一道思维量挺大的题目

    考虑dp
    我们要唯一地确定一个状态,而由数据来看应该是一个二维状态
    我们先研究一下这个波动数列的性质:
    可以归纳出一下几点:
    ①交换i和i - 1的位置,仍为波动数列。也就是说,除非i和i - 1相邻,i和i - 1的剩余方案一一对应
    ②将序列的所有数取补【即(i)变为(n + 1 - i)】,仍为波动数列

    由性质②,我们可以只求出开头为峰的方案数,乘2就是所有方案数
    由此我们设(f[i][j])表示前(i)个整数的序列以(j)为第一个元素且为山峰的方案数
    ①如果(j)(j - 1)不相邻,由性质①,(f[i][j]+=f[i][j - 1])
    ②如果(j)(j - 1)相邻,那么就转移到了(i - 1)个的方案,但是此时(j - 1)为山谷,由性质②,转化为山峰,(f[i][j] += f[i - 1][i - j + 1])

    最后统计一下答案就做完了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 4205,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int f[2][maxn],n,p;
    int main(){
    	n = read(); p = read(); int pos = 0;
    	f[1][1] = 1;
    	for (int i = 2; i <= n; i++,pos ^= 1)
    		for (int j = 1; j <= i; j++)
    			f[pos][j] = (f[pos][j - 1] + f[pos ^ 1][i - j + 1]) % p;
    	int ans = 0;
    	for (int i = 2; i <= n; i++) ans = (ans + f[pos ^ 1][i]) % p;
    	printf("%d
    ",(ans * 2) % p);
    	return 0;
    }
    
    
  • 相关阅读:
    sourcetree删除github远程仓库文件
    怎样去掉wordpress中默认的未分类目录
    解决LNMP环境无法显示所有WordPress主题及无法编辑主题页面
    炫龙笔记本组合快捷键
    原版win10
    whmcs之全民idc
    putty登陆sourceforge.net(设置登录)
    putty登陆sourceforge.net(密钥的设置)
    当android studio一直显示gradle compile dependency
    android与后台请求的例子
  • 原文地址:https://www.cnblogs.com/Mychael/p/8559599.html
Copyright © 2011-2022 走看看