题解 CF567F 【Mausoleum】

从放第一本书开始推,每次放两本相同高度的,设 (f_{i,j}) 为左边放i本书,右边放j本书的方案,放书的时候判断一下是否合法,如果合法,(f_{i,j}) += (f_{i-2,j}) , (f_{i-1,j-1}) , (f_{i,j-2}) ,这个方程应该不难理解**

至于条件可以用邻接表,注意一下邻接表的数据范围,因为书的位置有200个,正反都存一遍就好了

符号的正反:注意与 >= 相对的是 <= , 不是 <**

这是我用了 N(N>20) 次调试换来的······

得到的结果要除以3,因为当放最后两本书时,(f_{i-2,j} == f_{i-1,j-1} == f_{i,j-2})

具体见代码:

#include<bits/stdc++.h>
using namespace std;
long long n,f[210][210],tot,k,ans;
long long head[210],next11[410],ver[410],edge[410];
//一定开long long,一定开long long,一定开long long
void add(long long x,long long y,long long z){
    next11[++tot]=head[x],ver[tot]=y,edge[tot]=z,head[x]=tot;
}//邻接表

bool spfa(long long l,long long r,long long ll,long long rr){
//寻找出边,l表示放的两本书中左边的那本,r是右边那本,
//ll表示没有放书的区间的左端点,rr表示右端点,
//可知 ll~rr 中的书高度都大于将要放的两本书
    for(int i=head[l];i;i=next11[i])
    {
        int y=ver[i],z=edge[i];
        if(y==r){
            if(z==2||z==4) return false;
        }//特判,等于的情况只可能:出边为放的另一本书的位置
        else if(z<=2) {
            if(y<ll||y>rr) return false;
        }
        else if(z>=4) {
            if(y>ll&&y<rr) return false;
        }
        else if(z==3) return false;
    }//寻找与左端点有关的条件
    for(long long i=head[r];i;i=next11[i])
    {
        long long y=ver[i],z=edge[i];
        if(y==l){
            if(z==2||z==4) return false;
        }
        else if(z<=2) {
            if(y<ll||y>rr) return false;
        }
        else if(z>=4) {
            if(y>ll&&y<rr) return false;
        }
        else if(z==3) return false;
    }//同上
    return true;
}

int main(){
    cin>>n>>k;
    for(int i=1;i<=k;i++)
    {
        long long x,y,z=0;
        string c;
        cin>>x>>c>>y;
        if(c[1]=='=')
        {
            if(c[0]=='<') z=1;
            else z=5;
        }
        else {
            if(c[0]=='=') z=3;
            if(c[0]=='<') z=2;
            if(c[0]=='>') z=4;
        }
        if(x==y)
        {
            if(z==2||z==4)
            {
                cout<<0;
                return 0;
            }
            else continue;
        }
        add(x,y,z);
        add(y,x,6-z);//懂我为什么强调了吧
    }
    f[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=2*i;j++)
        {
            if(j>=2&&(k==0||spfa(j-1 , j , j+1 , 2*n-2*i+j)))
                f[j][2*i-j]+=f[j-2][2*i-j];
            if(j>=1&&2*i-j>=1&&(k==0||spfa( j , 2*n-2*i+j+1 , j+1 , 2*n-2*i+j)))
                 f[j][2*i-j]+=f[j-1][2*i-j-1];
            if(2*i-j>=2&&(k==0||spfa(2*n-2*i+j+1 , 2*n-2*i+j+2 , j+1 , 2*n-2*i+j)))
                f[j][2*i-j]+=f[j][2*i-j-2];
        }//自行理解,最好画个图
    }
    for(int i=0;i<=2*n;i++) ans+=f[i][2*n-i];//ans累加,
    cout<<ans/3;//重要
    return 0;
}
原文地址:https://www.cnblogs.com/ajy-shi-cj-zui-cai/p/10386726.html