BZOJ 1925: [Sdoi2010]地精部落 dp
2017-06-25 10:57
337 查看
1925: [Sdoi2010]地精部落
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1384 Solved: 855
[Submit][Status][Discuss]
Description
传说很久以前,大地上居住着一种神秘的生物:地精。 地精喜欢住在连绵不绝的山脉中。具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到N 之间的正 整数。 如果一段山脉比所有与它相邻的山脉都高,则这段山脉是一个山峰。位于边 缘的山脉只有一段相邻的山脉,其他都有两段(即左边和右边)。 类似地,如果一段山脉比所有它相邻的山脉都低,则这段山脉是一个山谷。 地精们有一个共同的爱好——饮酒,酒馆可以设立在山谷之中。地精的酒馆不论白天黑夜总是人声鼎沸,地精美酒的香味可以飘到方圆数里的地方。 地精还是一种非常警觉的生物,他们在每座山峰上都可以设立瞭望台,并轮 流担当瞭望工作,以确保在第一时间得知外敌的入侵。 地精们希望这N 段山脉每段都可以修建瞭望台或酒馆的其中之一,只有满足 这个条件的整座山脉才可能有地精居住。 现在你希望知道,长度为N 的可能有地精居住的山脉有多少种。两座山脉A 和B不同当且仅当存在一个 i,使得 Ai≠Bi。由于这个数目可能很大,你只对它 除以P的余数感兴趣。
Input
仅含一行,两个正整数 N, P。Output
仅含一行,一个非负整数,表示你所求的答案对P取余 之后的结果。Sample Input
4 7Sample Output
3HINT
对于 20%的数据,满足 N≤10;
对于 40%的数据,满足 N≤18;
对于 70%的数据,满足 N≤550;
对于 100%的数据,满足 3≤N≤4200,P≤109
不就是膝盖吗,给了 Orz
一个多月前“过”了这道题,还自欺欺人地认为懂了这道题,这直接导致了昨晚多校联测2的T3爆炸,现在想来简直是道水题,不过还是要有“懂得这题怎么做”的前提。。。地精部落这道题可以约化为另一个问题:对于n的排列,告诉你每个数相比于前一个数是大了、小了、还是都可以,求这样的排列的方案数。
先说这一题叭,看过很多其他人的题解,依然是云里雾里,因此我会写的详细一点。我的写法可能与其他人有些不同,但是本质是完全一样的。
首先令f(i, j)表示已经考虑完i的排列了,最后一个数是j,且它为山谷的方案数。这里特别注意!这个i的排列并不一定非要是闭区间[1, i]里的数!这种排列仅仅表示一个大小关系,一种相对的关系,有种离散化的感觉(也可以理解为考虑完i个数了,最后一个数是其中第j小的,且它为山谷的方案数)。这一点非常重要,一定要理解,如不理解可以先往下看,我后面会举个例子。类似地,令g(i,
j)表示已经考虑完i的排列了,最后一个数是j,且它为山峰的方案数。那么状态转移方程就是:
①
为什么是这样呢?首先f数组的值一定是从g数组转移过来的,因为如果这个是山谷,那么上一个就是山峰。那么为什么等于后面那一串呢?考虑这个例子,7253,这是你填完最后一个数字3后的某个方案。很显然,这种方案应该属于状态f(4,
2),因为已经考虑4个数了,3是其中第2小的。那么f(4, 2)这种状态可以从g(3, 2)与g(3, 3)转移过来,在7253这个例子中,f(4, 2)是从g(3, 2)转移过来的,因为在725中,5是第2小的。那么前i - 1个数中,最小能小到多少呢?(当然是考虑最小的,因为越大,就越可能转移到当前状态,所以最大能大到第i - 1小)答案是能小到j。因为前i个数中第j小的,必然比前i - 1个数中第j小的要小!可以通过刚刚7253这个例子来感受一下,3是前4个数中第2小的,5是前3个数中第2小的。
这个弄懂了之后,我们又可以发现一个很容易发现、非常显然的结论:把一个符合条件的n的排列,对于没一个数i,将其改为n + 1 - i,新的排列依然符合条件,并且原来的山峰变成山谷,山谷变成山峰,因此有:
②
联立①②,得
用一个辅助变量s,就可以O(1)转移了,最后ans = (f
[1] + f
[2] + ... + f
) * 2,因为f表示的是最后一个为山谷,根据那个显然的结论,可以得到等量的最后一个为山峰的方案数。在加一个滚动数组压缩空间就可以过了。
转载传送门
#include<cmath> #include<ctime> #include<cstdio> #include<cstring> #include<cstdlib> #include<complex> #include<iostream> #include<algorithm> #include<iomanip> #include<vector> #include<string> #include<bitset> #include<queue> #include<map> #include<set> using namespace std; typedef long long ll; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();} return x*f; } inline void print(ll x) {if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar('0'+x%10);} const int N=4500; int f [2]; int main() { int n=read(),mod=read(); if(n==1){puts("1");return 0;} int now=0;f[1][0]=1; for(int i=2;i<=n;i++) { now^=1; for(int j=1;j<=n;j++) if(j<=i)(f[j][now]=f[i-j][now^1]+f[j-1][now])%=mod; else f[j][now]=f[j-1][now]; } print((f [now]<<1)%mod);puts(""); return 0; } /* 4 7 3 */
相关文章推荐
- [BZOJ1925][Sdoi2010]地精部落(抖动序列dp)
- bzoj 1925: [Sdoi2010]地精部落【dp】
- bzoj 1925 [Sdoi2010]地精部落 dp
- bzoj1925: [Sdoi2010]地精部落(Dp)
- bzoj1925 [Sdoi2010] 地精部落【DP】
- BZOJ 1925: [Sdoi2010]地精部落( dp )
- BZOJ1925 [Sdoi2010]地精部落 【dp】
- BZOJ[1925]Sdoi[Sdoi2010]洛谷[P2467]地精部落 DP,滚动数组
- [DP Euler Zigzag Number] BZOJ 1925 [Sdoi2010]地精部落
- [BZOJ 1925][SDOI 2010] 地精部落 DP/递推
- [Bzoj1925]&[SDOI2010]地精部落 DP
- bzoj 1925: [Sdoi2010]地精部落(dp)
- bzoj 1925 [Sdoi2010]地精部落(DP)
- [bzoj1925][Sdoi2010][地精部落] (序列动态规划)
- bzoj1925: [Sdoi2010]地精部落
- bzoj1925 [Sdoi2010]地精部落
- BZOJ 1925 [Sdoi2010]地精部落
- 动态规划 BZOJ 1925: [Sdoi2010]地精部落
- 【bozj 1925】[Sdoi2010]地精部落 (dp)
- 【BZOJ1925】【Sdoi2010】地精部落 动规 不知语,人已醉。 Euler Zigzag Number