【Luogu】P1879玉米田(状压DP)

题目链接

数据范围这么小,难度又这么大,一般就是状态压缩DP了。

对输入进行处理,二进制表示每一行的草地状况。如111表示这一行草地肥沃,压缩成7.

所以f[i][j]表示第i行状态为j时的方案数

状态j指的是一个二进制集合,有牛在吃草的位置是1,不再吃草的位置是0

f[i][j]=Sum(f[i-1][k])

限制:(1) j必须是草地状况的子集。很好理解,如果有牛在贫瘠草地上吃草……会被投诉到动物保护协会的

(2) j 的相邻两个位置不能都是1。 代码表示为!(j&(j<<1)

(3) k 的上述两个限制。

(4) k和j没有交集。这样可以保证没有相邻两个位置是1。 

代码如下

复制代码
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<iostream>
#define mod 100000000
#define Max ((1<<m)-1)
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int f[20][200000]={1};
int s[20];

int ans;
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int x=read();
            s[i]=(s[i]<<1)+x;
        }
    for(int i=1;i<=n;++i)
        for(int j=0;j<=Max;++j){
            if(((j|s[i])!=s[i])||(j&(j<<1)))    continue;
            for(int k=0;k<=Max;++k){
                if(((k|s[i-1])!=s[i-1])||(k&(k<<1))||(k&j))    continue;
                f[i][j]=(f[i][j]+f[i-1][k])%mod;
            }
        }
    for(int i=0;i<=Max;++i)
        ans=(ans+f[n][i])%mod;
    printf("%d",ans);
    return 0;
}
复制代码

 

posted @   Konoset  阅读(219)  评论(0编辑  收藏  举报
编辑推荐:
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 2025成都.NET开发者Connect圆满结束
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络
点击右上角即可分享
微信分享提示