码迷,mamicode.com
首页 > 其他好文 > 详细

[Sdoi2010]地精部落

时间:2017-03-24 23:07:24      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:[1]   scan   序列   记忆化搜索   优化   php   代码   ring   时间   

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 low
ll 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]地精部落

标签:[1]   scan   序列   记忆化搜索   优化   php   代码   ring   时间   

原文地址:http://www.cnblogs.com/shenben/p/6613695.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!