首页 > 代码库 > [Sdoi2010]地精部落

[Sdoi2010]地精部落

1925: [Sdoi2010]地精部落

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1300  Solved: 800
[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 7

Sample Output

3

HINT


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

Source

第一轮Day2

技术分享
/*Orz 魏铭。想出来满分做法。。但是只能70分。首先,设状态f[i][H][0/1]表示序列posi是H,且为山峰/山谷。然后转移很显然。不过实现只能强打记忆化搜索。为什么呢?因为他是一个排列。转递推就要状压。就是用bitset也会爆。抛开空间不讲。时间也过不了。为什么?转移时O(n)的。如何优化?用前缀和优化变为O(1)。在处理好空间且保证状态正确的前提下,转成递推,用前缀和转移就好了。当时也想到了,但,写不出来。当场 魏铭 就用一种很神奇的方法,解决了我的问题,然,我还是看不懂。码力太弱了。。。此题对我感触很大。思维:从裸暴力->状压剪枝->换状态->换状态->换状态->优化->正解思路≠>正解代码(码力弱)。*/#include<cstdio>#include<cstring>#include<algorithm>#define set(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);using namespace std;typedef long long ll;const int N=555;int n,vis[N];ll f[N][N][2];ll ans,mod;//d=1 high//d=0 lowll dfs(int cur,int h,bool d){    ll &res=f[cur][h][d];    if(~res) return res;    res=0;    if(cur>=n) return res=1;     if(d){        for(int i=1;i<h;i++){            if(!vis[i]){                vis[i]=1;                res+=dfs(cur+1,i,!d);                vis[i]=0;            }        }    }    else{        for(int i=h+1;i<=n;i++){            if(!vis[i]){                vis[i]=1;                res+=dfs(cur+1,i,!d);                vis[i]=0;            }        }    }    return res%=mod;}inline void DFS(){    for(int i=1;i<=n;i++){        vis[i]=1;        dfs(1,i,0);        dfs(1,i,1);        vis[i]=0;    }    for(int i=1;i<=n;i++){        ans=(ans+f[1][i][0]+f[1][i][1])%mod;    }}int main(){    set(goblin);    memset(f,-1,sizeof f);    scanf("%d%I64d",&n,&mod);    if(n==1){printf("%I64d",1LL%mod);}    if(mod==1){printf("0");}    DFS();    printf("%I64d",ans);    return 0;} /*附魏铭100分代码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>using namespace std;#define zbwmqlw#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))#define abs(x) ((x)>0?(x):-(x))#define pow(x) (1<<(x))const int inf=0x3f3f3f3f;typedef __int64 LL;template<class T> void checkmin(T &a,const T &b) {if (b<a) a=b;}template<class T> void checkmax(T &a,const T &b){if (b>a) a=b;}const int N=4300;int a[20];bool vis[20],now,last;int n,ans;LL f[2][N][2],mo;void dfs(int depth){    if (depth==n+1) {        ++ans;        return;    }    int i;    for (i=1;i<=n;++i) if (!vis[i]) {        a[depth]=i;        if (depth>2 && (a[depth]>a[depth-1])==(a[depth-1]>a[depth-2])) continue;        vis[i]=true;        dfs(depth+1);        vis[i]=false;    }}void solvedfs(){    ans=0;    dfs(1);    printf("%d %d\n",n,ans);    exit(0);}void solvedp(){    int i,j,k;    now=true; last=false;    memset(f[now],0,sizeof(f[now]));    for (j=0;j<n;++j) f[now][j][0]=f[now][j][1]=1;    for (i=2;i<=n;++i) {        now^=1; last^=1;        memset(f[now],0,sizeof(f[now]));        LL s0=0,s1=0;        for (k=0;k+i-1<=n;++k) s1+=f[last][k][1];        for (j=0;j+i<=n;++j) {            s0+=f[last][j][0];            s1-=f[last][j][1];            f[now][j][1]=s0%mo;            f[now][j][0]=s1%mo;        }    }    printf("%I64d\n",(f[now][0][0]+f[now][0][1])%mo);}int main(){    freopen("goblin.in","r",stdin);    freopen("goblin.out","w",stdout);    scanf("%d%I64d",&n,&mo);    solvedp();    fclose(stdout);}*/
70分心痛代码

AC思路:http://blog.csdn.net/mrazer/article/details/53426415?locationNum=12&fps=1

#include<cstdio>#define set(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);using namespace std;const int N=4201;int f[2][N],n,now,mod,ans;int main(){    set(goblin);    scanf("%d%d",&n,&mod);    f[now][1]=1;    for(int i=2;i<=n;i++){        now^=1;        for(int j=1;j<=i;j++){            f[now][j]=(f[now][j-1]+f[now^1][i-j+1])%mod;        }    }    for(int i=1;i<=n;i++) ans=(ans+f[now][i])%mod;    printf("%d\n",ans*2%mod);    return 0;}

 

 

[Sdoi2010]地精部落