51 nod 1522 上下序列——序列dp

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1522

很好的思想。考虑从小到大一对一对填数,这样也能对它的大小限制做一些操作了。

因为从小到大,所以只能全填在左边、全填在右边、两边各填一个。记录左边填到了哪个位置,就可知右边填到了哪个位置。转移之前判断一下这样填是否合法即可。

新的不合法的状态只会和现在填的两个位置有关。

注意输入格式!!符号前后有空格!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=40,M=105;
int n,m,x[M],y[M],sgn[M],tx,ty;
ll dp[N][N<<1],ans;
char ch[20];
bool check(int p0,int p1,int r,int fx)
{
    //printf("p0=%d p1=%d r=%d fx=%d\n",p0,p1,r,fx);
    for(int i=1;i<=m;i++)
        if(sgn[i]==0&&
           ( ( (x[i]==p0||x[i]==p1)&&y[i]!=p0&&y[i]!=p1)||
             ( (y[i]==p0||y[i]==p1)&&x[i]!=p0&&x[i]!=p1) ) )
            return 0;//以前都合法,不合法仅出现在p0、p1位置上
    if(!fx)
    {
        for(int i=1;i<=m;i++)
        {
            //printf("sgn[%d]=%d\n",i,sgn[i]);
            if(sgn[i]==1||sgn[i]==2)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==2)swap(tx,ty);
                //printf("tx=%d ty=%d p0=%d p1=%d r=%d\n",tx,ty,p0,p1,r);
                if((ty==p0||ty==p1)&&tx>=p0&&tx<r) return 0;
            }
            if(sgn[i]==3||sgn[i]==4)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==4)swap(tx,ty);
                if((ty==p0||ty==p1)&&tx>p1&&tx<r) return 0;
            }
        }
    }
    if(fx==1)
    {
        for(int i=1;i<=m;i++)
        {
            if(sgn[i]==1||sgn[i]==2)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==2)swap(tx,ty);
                if((ty==p0||ty==p1)&&tx<=p1&&tx>r) return 0;
            }
            if(sgn[i]==3||sgn[i]==4)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==4)swap(tx,ty);
                if((ty==p0||ty==p1)&&tx<p0&&tx>r) return 0;
            }
        }
    }
    if(fx==2)
    {
        for(int i=1;i<=m;i++)
        {
            if(sgn[i]==1||sgn[i]==2)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==2)swap(tx,ty);
                if((ty==p0||ty==p1)&&tx>=p0&&tx<=p1) return 0;
            }
            if(sgn[i]==3||sgn[i]==4)
            {
                tx=x[i];ty=y[i];
                if(sgn[i]==4)swap(tx,ty);
                if((ty==p0||ty==p1)&&tx>p0&&tx<p1) return 0;
            }
        }
    }
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);ch[0]=getchar();
    while(ch[0]!=‘\n‘)ch[0]=getchar();
    for(int i=1,len=0,j;i<=m;i++,len=0)
    {
        ch[++len]=getchar();
        while(ch[len]!=‘\n‘)ch[++len]=getchar();
        for(j=1;j<len;j++)
        {
            if(ch[j]>=‘0‘&&ch[j]<=‘9‘)
                x[i]=(x[i]<<3)+(x[i]<<1)+ch[j]-‘0‘;
            else break;
        }
        while(ch[j]==‘ ‘)j++;
        //printf("j=%d chj=(%c)\n",j,ch[j]);
        if(ch[j]==‘=‘) sgn[i]=0,j++;
        else if(ch[j]==‘<‘&&ch[j+1]==‘=‘)sgn[i]=3,j+=2;
        else if(ch[j]==‘>‘&&ch[j+1]==‘=‘)sgn[i]=4,j+=2;
        else if(ch[j]==‘<‘)sgn[i]=1,j++;
        else if(ch[j]==‘>‘)sgn[i]=2,j++;
        while(ch[j]==‘ ‘)j++;
        //printf("j=%d chj=(%c)\n",j,ch[j]);
        for(;j<len;j++)
            y[i]=(y[i]<<3)+(y[i]<<1)+ch[j]-‘0‘;
        //printf("x=%d sgn=%d y=%d\n",x[i],sgn[i],y[i]);
    }
    dp[0][0]=1;
    for(int i=0,lm;i<n;i++)
    {
        lm=(i<<1);
        for(int j=0,r;j<=lm;j++)
        {
            //if(dp[i][j])printf("dp[%d][%d]=%lld\n",i,j,dp[i][j]);
            r=(n<<1)-(lm-j)+1;
            if(check(j+1,j+2,r,0))
                dp[i+1][j+2]+=dp[i][j];
                    //printf("dp[%d][%d]=%lld(%d,%d)\n",i+1,j+2,dp[i+1][j+2],i,j);
            if(check(r-2,r-1,j,1))
                dp[i+1][j]+=dp[i][j];
            //printf("dp[%d][%d]=%lld(%d,%d)\n",i+1,j,dp[i+1][j],i,j);
            if(check(j+1,r-1,0,2))
                dp[i+1][j+1]+=dp[i][j];
                    //printf("dp[%d][%d]=%lld(%d,%d)\n",i+1,j+1,dp[i+1][j+1],i,j);
        }
    }
    int lm=(n<<1);
    for(int j=0;j<=lm;j++) ans+=dp[n][j];
    printf("%lld\n",ans/3);
    return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/9672719.html

时间: 2024-08-29 23:28:26

51 nod 1522 上下序列——序列dp的相关文章

51 nod 1055 最长等差数列(dp)

1055 最长等差数列 基准时间限制:2 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 8 9 10 12 13 14 等差子数列包括(仅包括两项的不列举) 1 3 5 1 5 9 13 3 6 9 12 3 8 13 5 9 13 6 8 10 12 14 其中6 8 10 12 14最长,长度为5. Input 第1行:N,N为正整数的数量(3 <= N <= 10000). 第2 - N+1行

51 nod 1610 路径计数(Moblus+dp)

1610 路径计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 路径上所有边权的最大公约数定义为一条路径的值. 给定一个有向无环图.T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模). Input 第一行两个整数n和m,分别表示有向无环图上的点数和边数.(1<=n<=100,1<=m<=50,000) 第2~m+1行每行三个数x,y,z,表示有一条从x到y权值为z的边.(1

codevs 1962 马棚问题--序列型DP

1962 马棚问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 每天,小明和他的马外出,然后他们一边跑一边玩耍.当他们结束的时候,必须带所有的马返回马棚,小明有K个马棚.他把他的马排成一排然后跟随它走向马棚,因为他们非常疲劳,小明不想让他的马做过多的移动.因此他想了一个办法:将马按照顺序放在马棚中,后面的马放的马棚的序号不会大于前面的马放的马棚的序号.而且,他不想他的K个马棚中任何一个空置,也不想任何一匹马在外面.已知共有黑

51 nod 1495 中国好区间

1495 中国好区间 基准时间限制:0.7 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 阿尔法在玩一个游戏,阿尔法给出了一个长度为n的序列,他认为,一段好的区间,它的长度是>=k的,且该区间的第k大的那个数,一定大于等于T.那么问题来了,阿尔法想知道有多少好的区间. 由于阿尔法的序列长度实在是太大了,无法在规定时间内读入. 他想了一个绝妙的方法. 读入a[0],b,c,p,则a[i]=(a[i-1]*b+c)mod p. 样例解释: a1~a5分别为47,135,247,3

51 nod 1427 文明 (并查集 + 树的直径)

1427 文明 题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 安德鲁在玩一个叫“文明”的游戏.大妈正在帮助他. 这个游戏里面有n个城市和m条双向的道路.城市从1到n编号.对于每一对城市,他们之间要么有唯一的一条道路,要么就是不可互达.一条道路的定义是一个包含不同城市的序列 v1, v2,...,vk ,  vi  和  vi+1 (1≤ i < k)之间有直接的一条道路相连.这条道路的长度是k-1.两个城市在同一区域的

51 nod 1394 1394 差和问题(线段树)

1394 差和问题基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个多重集合S(即里面元素可以有重复),初始状态下有n个元素,对他进行如下操作: 1.向S里面添加一个值为v的元素.输入格式为1 v 2.向S里面删除一个值为v的元素.输入格式为2 v 3.询问S里面的元素两两之差绝对值之和.输入格式为3 对于样例, 操作3,|1-2|+|1-3|+|2-3|=4 操作1 4之后,集合中的数字为1 2 3 4 操作3,|1-2|+|1-3|+|2-3|+|1-

51 nod 1766 树上的最远点对(线段树+lca)

1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d} (PS 建议使用读入优化) Input 第一行一个数字 n n<=100000. 第二行到第n行每行三个数字描述路的情况, x,y,z (1<=x,y<=n,1<

51 nod 1439 互质对(Moblus容斥)

1439 互质对 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 有n个数字,a[1],a[2],…,a[n].有一个集合,刚开始集合为空.然后有一种操作每次向集合中加入一个数字或者删除一个数字.每次操作给出一个下标x(1 ≤ x ≤ n),如果a[x]已经在集合中,那么就删除a[x],否则就加入a[x]. 问每次操作之后集合中互质的数字有多少对. 注意,集合中可以有重复的数字,两个数字不同当且仅当他们的下标不同. 比如a[

51 nod 1188 最大公约数之和 V2

1188 最大公约数之和 V2 题目来源: UVA 基准时间限制:2 秒 空间限制:262144 KB 分值: 160 难度:6级算法题 给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和. 相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数): G=0; for(i=1;i<N;i++) for(j=i+1;j<=N;j++) { G+=gcd(i,j); } Input 第1行:1个数T,表示后面用作输入测试的数的数量.(1 <= T <= 5000