洛谷2593 [ZJOI2006]超级麻将——可行性dp

题目:https://www.luogu.org/problemnew/show/P2593

发现三个连续牌的影响范围只有3、相同牌的影响范围只有1之后就可以dp了。

O(100^7)T飞。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
int T,a[N];
bool dp[2][N][N][N],flag;
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
int main()
{
    T=rdn();
    while(T--)
    {
        for(int i=1;i<=100;i++)a[i]=rdn();
        for(int t=1;t<=100;t++)if(a[t]>=2)
        {
            a[t]-=2;
            memset(dp[1],0,sizeof dp[1]);
            dp[1][a[1]][a[2]][a[3]]=1;
            for(int i=3;i<=102;i++)
            {
                flag=0;int d=(i&1);
                memset(dp[!d],0,sizeof dp[!d]);
                for(int x=0;x<=a[i-2];x++)
                    for(int y=0;y<=a[i-1];y++)
                        for(int z=0;z<=a[i];z++)
                            if(dp[d][x][y][z])
                            {
                                int lm=min(x,min(y,z));
                                for(int k=0;k<=lm;k++)
                                {
                                    dp[!d][y-k][z-k][a[i+1]]|=(((x-k)%3==0)|((x-k)%4==0));
                                    if(dp[!d][y-k][z-k][a[i+1]])flag=1;
                                }
                            }
                if(!flag)break;
            }
            a[t]+=2;
            if(flag)break;
        }
        if(flag)printf("Yes\n");else printf("No\n");
    }
    return 0;
}
View Code

如果不枚举对子在哪而是带一个0/1在状态里的话可以少乘一个100。

如果不无脑记录前两个位置而是仅记录前一个位置、用三连的时候调用一下上一层的话可以少乘一个100。

  这是因为最后要的只有dp[ ][0][0][0],所以保存很多“之前位置还不是0”的状态比较浪费。

不枚举用了几个三连,而是每层用“从开头降到这里”更新一下本层,就能把”在本层用较少的三连“包括在“用单个位置从之前层降下来”。这样可以少乘一个100。

  这里调了好久!必须是“从开头降到这里”,而不能是“从这里降到0”;因为从“这里”降的话需要判断本层是否可行,但这个可行是包括 i-2 的状态的,自己仅记录前一个位置的dp不能存下。如果是”从开头降到这里“的话,本层目前一定是可行的。

O(100^4)卡过。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110;
int T,a[N];
bool dp[N][N][N][2];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
int main()
{
    T=rdn();
    while(T--)
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=100;i++)a[i]=rdn();
        dp[1][0][a[1]][0]=1;
        for(int i=1;i<=100;i++)
        {
            for(int x=a[i-1];x>=0;x--)
                for(int y=a[i];y>=0;y--)
                {
                    dp[i][x][y][1]|=dp[i][x][y+2][0];
                    
                    dp[i][x][y][0]|=dp[i][x][y+3][0];
                    dp[i][x][y][1]|=dp[i][x][y+3][1];
                    
                    dp[i][x][y][0]|=dp[i][x][y+4][0];
                    dp[i][x][y][1]|=dp[i][x][y+4][1];
                    //在a[i]变成各种y之后尝试一下从开头降到这里(先降后单个弄) 
                    dp[i][x][y][0]|=dp[i-1][a[i]-y][x+a[i]-y][0];
                    dp[i][x][y][1]|=dp[i-1][a[i]-y][x+a[i]-y][1];
                    
                    //在a[i]变成各种y之后尝试一下取完 
//                    dp[i][x][0][0]|=dp[i-1][y][x+y][0];//不能&dp[i][x+y][y],因含义是i-2==0 
//                    dp[i][x][0][1]|=dp[i-1][y][x+y][1];//不&的话会出错:0 3 0(原为2) 
                    //因为从当前降到0的话,需要判断当前是否可行
                    //可是降还需要i-2的也许有值,与表示“当前可行”的dp冲突,即无法表示当前是否可行 
                    //而“从开头”降的话,一定可行 
                    
                    //x之所以不是0,是因为这里用到dp[i-1][y][][] 
                    if(!x)
                    {
                        dp[i+1][y][a[i+1]][0]|=dp[i][0][y][0];
                        dp[i+1][y][a[i+1]][1]|=dp[i][0][y][1];
                    }
//                    if(i<=3)
//                    {
//                        if(dp[i][x][y][0])printf("dp[%d][%d][%d][%d]=%d\n",i,x,y,0,dp[i][x][y][0]);
//                        if(dp[i][x][y][1])printf("dp[%d][%d][%d][%d]=%d\n",i,x,y,1,dp[i][x][y][1]);
//                    }
                }
        }
        puts(dp[100][0][0][1]?"Yes":"No");
    }
    return 0;
}

 

posted on 2018-07-26 11:37  Narh  阅读(293)  评论(0编辑  收藏  举报

导航