AGC026D Histogram Coloring 题解

news/2024/9/18 19:41:34/文章来源:https://www.cnblogs.com/BigSmall-En/p/18415789

[AGC026D] Histogram Coloring 题解

给定 \(n\) 列的网格,每列高为 \(h_i\),将每个格子染色成红色或蓝色,使得每个 \(2\times 2\) 的区域都恰好有两个蓝格子和两个红格子,求方案数(对 \(10^9+7\) 取模)。

\(1\leq n\leq 100,1\leq h_i\leq 10^9\)

性质

为了方便讲述,先假设 \(h_i=h_{i+1}\),第 \(i\) 列第 \(j\) 行的染色状态记为 \(a_{i,j}\)。下面这些东西画一下一下就明白了。

如果存在 \(a_{i,j}=a_{i,j+1}\),就是说前一列中出现两个连续颜色相同格子,那么后一列中每格颜色必须和前一列相反。反之如果前一列颜色是交错的,那么后一列颜色既可以和前一列相同,也可以和前一列相反(答案 \(\times 2\)

显然 \(h_i\) 不一定等于 \(h_{i+1}\),如果 \(a_{i,j}=a_{i,j+1},\forall k<j,a_{i,k}\neq a_{i,k+1}\)\(h_{i+1}\leq j\),那么前一列中连续同色格就影响不到后一列;如果 \(h_{i+1}\geq j+1\),那么后一列 \(j+1\) 及往上的行就可以随便染色,前一列无法限制。

\(h_i\leq 10^3\)

首先让我们忽略 \(h_i\) 是个 \(10^9\) 的数,考虑它和 \(n\) 同量级怎么做。

我们定义 \(dp_{i,j}\) 为考虑到第 \(i\) 列,且第 \(i\) 列前 \(j\) 个格子颜色都是交错而 \(a_{i,j}\neq a_{i,j+1}\) 的方案数。

如果 \(h_{i}>h_{i-1}\),那么 \(a_{i,h_i}\sim a_{i,h_{i+1}}\) 是可以自由填色不受前一列限制的,有转移

\[dp_{i,j}=dp_{i-1,j}\times 2^{a_i-a_{i-1}}\quad j\leq a_{i-1} \]

而对于 \(j>a_{i-1}\) 的情况,该列可以自由填数的位置就是 \(j+1\sim a_i\) 了,又需要兼顾前一列的答案,有转移

\[dp_{i,j}=dp_{i-1,a_{i-1}}\times 2^{a_i-j} \quad a_{i-1}<j<a_i \]

对于 \(j=a_{i}\),需要特殊考虑,根据前面性质,颜色交错要么和前列相同要么相反

\[dp_{i,a_i}=dp_{i-1,a_{i-1}}\times 2 \]

如果 \(h_i\leq h_{i-1}\),可以得到以下转移,方法原理比上面一种情况还简单一些

\[dp_{i,j}=dp_{i-1,j} \quad j< a_i\\ dp_{i,a_i}=\sum_{j=a_i}^{a_{i+1}}2\times dp_{i-1,j} \]

统计答案就是 \(\sum a_{n,j}\),总的复杂度是 \(O(nh)\) 的。

拓展到 \(10^9\)

\(h_i\) 离散化,数据存在 \(lis\) 数组里面,然后我们定义 \(f_{i,j}=\sum\limits_{k=lis_{j-1}+1}^{lis_j}dp_{i,k}\)

对于第二个式子 \(dp_{i,j}=dp_{i-1,a_{i-1}}\times 2^{a_i-j} \quad a_{i-1}<j<a_i\),可以得到

\[f_{i,j}=dp_{i-1,a_{i-1}}\times (2^{a_i-lis_j}+2^{a_i-lis_j+1}+\cdots 2^{a_i-lis_{j-1}-1}) \]

等比数列求和即可。对于其他的式子,转移比较显然。

重点是我们会发现我们的 \(dp_{i,a_i}\) 是特殊判断的,也就是说我们用 \(f_{i,k}\) (其中 \(lis_k=a_i\))是不能根据上面式子转移的,我们需要重新定义一下 \(f_{i,k}=dp_{i,a_i}\) 而不是一段数的和。实现方法很简单,离散化的时候将 \(a_i-1\) 加入 \(lis\) 数组即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P=1000000007;
const int N=103;
int n;ll h[N],lis[N*N],a[N],dp[N][N*2];int tot;
inline ll fpr(ll b,ll t,ll x=1ll){for(;t;t>>=1,b=b*b%P)if(t&1)x=x*b%P;return x;
}
inline ll sumr(ll l,ll r){//2^l+...+2^rreturn fpr(2ll,l)*(fpr(2ll,r-l+1)-1+P)%P;
}
int main(){scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%lld",&h[i]);lis[++tot]=h[i];if(h[i]>1)lis[++tot]=h[i]-1;}lis[++tot]=1;sort(lis+1,lis+1+tot);tot=unique(lis+1,lis+1+tot)-lis-1;for(int i=1;i<=n;++i)a[i]=lower_bound(lis+1,lis+1+tot,h[i])-lis;a[0]=1;dp[0][a[0]]=1;for(int i=1;i<=n;++i){if(a[i]>a[i-1]){for(int j=1;j<a[i];++j){			if(j<=a[i-1])dp[i][j]=dp[i-1][j]*fpr(2ll,lis[a[i]]-lis[a[i-1]])%P;else dp[i][j]=dp[i-1][a[i-1]]*sumr(lis[a[i]]-lis[j],lis[a[i]]-lis[j-1]-1)%P;}dp[i][a[i]]=2*dp[i-1][a[i-1]]%P;}else{for(int j=1;j<=a[i-1];++j){if(j<a[i])dp[i][j]=dp[i-1][j];else dp[i][a[i]]=(dp[i][a[i]]+2*dp[i-1][j])%P;}}}ll ans=0;for(int j=1;j<=a[n];++j)ans=(ans+dp[n][j])%P;printf("%lld\n",ans);return 0;
}

后记

高数课上推的,当时还没考虑 \(h_i\) 值域的问题,但是发现可以比较简单得拓展,虽然最后还是码了快 \(1\) 个小时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/797846.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态规划——数学模型精解

动态规划是运筹学的一个分支,主要用于求解多阶段决策过程的优化问题。1950年代初,R.E. Bellman提出了最优性原理,将复杂的多阶段问题分解为一系列单阶段问题逐步求解,开创了动态规划这一方法。1957年,他出版了《Dynamic Programming》,成为该领域的经典著作。动态规划自问…

C#实现系统登录

1, 新建窗口frm_Loginusing System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;namespace WindowsFormsA…

深度学习(FCN)

FCN是全卷积网络,用于做图像语义分割。通常将一般卷积网络最后的全连接层换成上采样或者反卷积网络,对图像的每个像素做分类,从而完成图像分割任务。 网络结构如下:这里并没有完全按照原始网络结构实现,而是尝试upsample和convTranspose2d结合的方式,看看有什么效果。 下…

多线程五-线程通信之wait与notify

wait与notify用于syncronized的线程间通信的一种,wait用来阻塞线程并释放锁,notify用来唤醒线程。他们与condition作用基本一致,但是由于syncronized为jdk实现,阅读源码有难度,所以通过了解其原理,用来帮助我们后续理解condition的源码。 可以通过下面一张图来理解:下面…

帝国cms忘记了后台密码怎么办

如果你忘记了帝国CMS(EmpireCMS)的后台管理员密码,可以通过以下步骤来重置密码: 方法 1: 通过数据库重置密码登录数据库:使用数据库管理工具(如phpMyAdmin)连接到你的数据库。 登录数据库管理界面。找到用户表:通常表名为 phome_enewsuser(具体表名可能有所不同)。 打…

如何恢复对帝国CMS的访问,忘记账号密码的解决方案

如果你忘记了帝国CMS的后台管理员账号和密码,可以通过以下步骤来恢复对系统的访问: 方法 1: 通过数据库重置密码登录数据库:使用数据库管理工具(如phpMyAdmin)连接到你的数据库。 登录数据库管理界面。找到用户表:通常表名为 phome_enewsuser(具体表名可能有所不同)。 …

编程日记 后端tags过滤器

编程日记 后端tags过滤器这样查出来了所有的信息,不对 检查是这个地方有问题改掉 @Overridepublic List<User> searchUsersByTags(List<String> tagNameList) {//1.先查询所有用户QueryWrapper<User> queryWrapper = new QueryWrapper<>();List<Us…

PbootCms忘记后台管理员密码这样找回

如果你忘记了PbootCMS后台管理员的密码,可以通过以下步骤来重置密码: 方法 1: 使用官方提供的密码重置工具下载密码重置工具:下载官方提供的密码重置工具 resetpw.php。 将 resetpw.php 文件上传到网站根目录。访问重置工具:在浏览器中访问 http://[您的域名]/resetpw.php。…

织梦CMS 忘记后台管理员密码的一种解决方法

如果你忘记了织梦CMS(Dedecms)的后台管理员密码,并且拥有对MySQL数据库的操作权限,可以按照以下步骤重置密码: 步骤 1: 登录 MySQL 数据库打开 MySQL 客户端,如 phpMyAdmin 或命令行工具。 登录 MySQL 数据库:sqlmysql -u 用户名 -p输入密码后登录。步骤 2: 选择对应的数…

编程日记 后端使用redis

编程日记 后端使用redis 问题:在写伙伴匹配系统的时候,要使用redis存储数据,需要在xml文件中设置spring.session.tore-type=redis 但是3.x版本的spring不再有这个参数。 那么怎么设置是否使用redis存储呢?只要导入了org.springframework.session包那就启用,不导入就不启用…

帝国cms网站忘记登陆账号密码怎么办

如果你忘记了帝国CMS的登录账号和密码,可以尝试以下方法来恢复访问权限:通过官方提供的找回功能:访问帝国CMS的登录页面。 查看是否有“忘记密码”链接。 点击此链接,并按照提示通过注册时绑定的邮箱或手机号来找回密码。手动重置数据库中的密码:使用数据库管理工具(如ph…

phpcmsV9 管理员密码丢失或忘记了怎么办

如果你在本地测试安装phpcmsV9时忘记了管理员密码,可以通过以下步骤手动重置密码: 方法/步骤打开数据库管理工具使用如phpMyAdmin这样的数据库管理工具连接到你的本地数据库。 通常,你可以通过访问 http://localhost/phpmyadmin/ 来打开phpMyAdmin。选择数据库和表选择你的p…