Atcoder 题面传送门 & 洛谷题面传送门

这是一道难度 Cu 的 AGC E,碰到这种思维题我只能说:not for me,thx

然鹅似乎 ycx 把题看错了?

首先这个平方与乘法比较喜闻乐见,很容易与组合联系在一起,于是我们不妨把题目条件翻译成组合的语言:

  • 有一排 \(n\) 个格子,你要在其中插入若干个隔板将其隔成若干段
  • 有 \(m\) 个特殊格子 \(a_1,a_2,\dots,a_m\),\(\forall i\in [1,m]\) 你禁止在 \(a_i\) 与 \(a_{i}+1\) 之间放隔板
  • 在相邻隔板之间的格子中需恰好放上一个黑球和一个白球(可以重合)

不难发现,上述题面中的”隔板“对应原题中的正方形边界,对于一段长度为 \(l\) 的段,在上面放一个黑球和一个白球的方案数为 \(l^2\),也就对应了原题面中的”平方“,而原题中的乘法在上述题面中被翻译成了乘法原理。因此我们就将这题与组合意义联系在了一起。

考虑设 \(dp_{i,j}\) 表示现在考虑了前 \(i\) 个位置,在当前位置到上一个隔板的区间中放上了 \(j\) 个球的方案数,其中 \(j\in [0,2]\)。

显然对于非特殊格子 \(i\) 我们有状态转移方程:

  • \(dp_{i+1,0}=dp_{i,0}+dp_{i,2}\)(在 \(i\) 与 \(i+1\) 之间放隔板或不放隔板)
  • \(dp_{i+1,1}=2dp_{i,0}+dp_{i,1}+2dp_{i,2}\)(如果放隔板,那么只能从 \(dp_{i,2}\) 转移过来,由于有黑白两种颜色的求所以乘个 \(2\);如果不放隔板,那么可以从 \(dp_{i,0},dp_{i,1}\) 转移过来,同理 \(dp_{i,0}\) 前的系数也需乘个 \(2\))
  • \(dp_{i+1,2}=dp_{i,0}+dp_{i,1}+2dp_{i,2}\)(如果放隔板,那么只能从 \(dp_{i,2}\) 转移过来;如果不放隔板,那么可以从 \(dp_{i,0},dp_{i,1},dp_{i,2}\) 转移过来,以上四种情况均只有一种放法,而 \(dp_{i,2}\) 前系数的 \(2\) 是因为 \(dp_{i,2}\) 出现了两次)

对于特殊格子 \(i\) 我们同样可以得到类似的状态转移方程:

  • \(dp_{i+1,0}=dp_{i,0}\)
  • \(dp_{i+1,1}=2dp_{i,0}+dp_{i,1}\)
  • \(dp_{i+1,2}=dp_{i,0}+dp_{i,1}+dp_{i,2}\)

那么这样转化有什么好处呢?在原题中我们直接 \(dp\) 不是太容易,或者说我们只能想出 1D1D 的 \(dp\) 状态。而在转化后的题面中则可以将转移写成常系数齐次递推的形式了。

由于上述状态转移方程以常系数齐次递推的形式出现,故我们可以把它写成矩阵的形式,即对于非特殊格子 \(i\),\(\begin{bmatrix}dp_{i+1,0}\\dp_{i+1,1}\\dp_{i+1,2}\end{bmatrix}=\begin{bmatrix}1&0&1\\2&1&2\\1&1&2\end{bmatrix}\begin{bmatrix}dp_{i,0}\\dp_{i,1}\\dp_{i,2}\end{bmatrix}\),对于特殊格子 \(i\),\(\begin{bmatrix}dp_{i+1,0}\\dp_{i+1,1}\\dp_{i+1,2}\end{bmatrix}=\begin{bmatrix}1&0&0\\2&1&0\\1&1&1\end{bmatrix}\begin{bmatrix}dp_{i,0}\\dp_{i,1}\\dp_{i,2}\end{bmatrix}\)。因此最后的 \(dp_n\) 可以写成一排 \(\begin{bmatrix}1&0&1\\2&1&2\\1&1&2\end{bmatrix}\) 和 \(\begin{bmatrix}1&0&0\\2&1&0\\1&1&1\end{bmatrix}\) 连乘的形式,其中 \(\begin{bmatrix}1&0&0\\2&1&0\\1&1&1\end{bmatrix}\) 的个数为 \(m\),显然矩乘算一下就好了,复杂度 \(m\log n\omega^3\),其中 \(\omega=3\)。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MOD=1e9+7;
int n,m;
struct mat{
ll a[3][3];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat res;
for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++)
res.a[i][j]+=a[i][k]*rhs.a[k][j];
for(int i=0;i<3;i++) for(int j=0;j<3;j++) res.a[i][j]%=MOD;
return res;
}
};
int main(){
mat x,y,ret;ret.a[0][0]=1;
x.a[0][0]=1;x.a[0][1]=0;x.a[0][2]=1;
x.a[1][0]=2;x.a[1][1]=1;x.a[1][2]=2;
x.a[2][0]=1;x.a[2][1]=1;x.a[2][2]=2;
y.a[0][0]=1;y.a[0][1]=0;y.a[0][2]=0;
y.a[1][0]=2;y.a[1][1]=1;y.a[1][2]=0;
y.a[2][0]=1;y.a[2][1]=1;y.a[2][2]=1;
scanf("%d%d",&n,&m);int pre=-1;
for(int i=1,v;i<=m;i++){
scanf("%d",&v);int stp=v-pre-1;
mat z=x;for(;stp;stp>>=1,z=z*z) if(stp&1) ret=z*ret;
ret=y*ret;pre=v;
} int stp=n-pre-1;
mat z=x;for(;stp;stp>>=1,z=z*z) if(stp&1) ret=z*ret;
printf("%d\n",ret.a[2][0]);
return 0;
}

upd on 2021.3.9:

事实上还有一种基于朴素 \(dp\) 的代数优化方法。

首先我们不考虑组合意义,就直接设 \(dp_i\) 表示考虑前 \(i\) 个格子并在 \(i\) 与 \(i+1\) 放上隔板的答案。显然对于非特殊点 \(dp_i=\sum\limits_{j=0}^{i-1}dp_j(i-j)^2\),否则 \(dp_i=0\)。

考虑直接着手优化这个式子,我们考虑 \(dp_{i+1}\) 的递推式,(这里假设 \(i+1\) 不是标记点,即 \(dp_{i+1}\ne 0\))显然 \(dp_{i+1}=\sum\limits_{j=0}^idp_j(i+1-j)^2\),考虑把最后一项单独提出来,即 \(dp_{i+1}=\sum\limits_{j=0}^{i-1}dp_j(i+1-j)^2+dp_i\),把括号打开即有 \(dp_{i+1}=\sum\limits_{j=0}^{i-1}dp_j(i-j)^2+2\sum\limits_{j=0}^{i-1}dp_j(i-j)+\sum\limits_{j=0}^{i-1}dp_j+dp_i\)

我们记 \(a_i=\sum\limits_{j=0}^{i-1}dp_j,b_i=\sum\limits_{j=0}^{i-1}dp_j(i-j),c_i=\sum\limits_{j=0}^{i-1}dp_j(i-j)^2\),那么显然 \(dp_i=c_i\),还是考虑上面 \(dp_{i+1}\) 的展开式,那么有 \(dp_{i+1}=a_i+2b_i+c_i+dp_i\),假设我们知道了 \(a_{i},b_{i},c_{i}\),考虑怎样求出 \(a_{i+1},b_{i+1},c_{i+1}\),分 \(i\) 我特殊点和 \(i\) 不是特殊点讨论:

  • 若 \(i\) 不是特殊点,那么

    • \(a_{i+1}=\sum\limits_{j=0}^{i-1}dp_j+dp_{i}=a_i+c_i\)
    • \(b_{i+1}=\sum\limits_{j=0}^{i-1}dp_j(i+1-j)+dp_{i}=\sum\limits_{j=0}^{i-1}dp_j(i-j)+\sum\limits_{j=0}^{i-1}dp_j+dp_i=b_i+a_i+c_i\)
    • \(c_{i+1}=dp_{i+1}=a_i+2b_i+c_i+dp_i=a_i+2b_i+2c_i\)
  • 若 \(i\) 是特殊点,那么
    • \(a_{i+1}=\sum\limits_{j=0}^{i-1}dp_j=a_i\)
    • \(b_{i+1}=\sum\limits_{j=0}^{i-1}dp_j(i+1-j)+dp_{i}=\sum\limits_{j=0}^{i-1}dp_j(i-j)+\sum\limits_{j=0}^{i-1}dp_j=b_i+a_i\)
    • \(c_{i+1}=dp_{i+1}=a_i+2b_i+c_i\)

上述式子也可写成矩阵的形式,即对于关键点 \(i\),\(\begin{bmatrix}a_{i+1}\\b_{i+1}\\c_{i+1}\end{bmatrix}=\begin{bmatrix}1&0&1\\1&1&1\\1&2&2\end{bmatrix}\times\begin{bmatrix}a_{i}\\b_{i}\\c_{i}\end{bmatrix}\),否则 \(\begin{bmatrix}a_{i+1}\\b_{i+1}\\c_{i+1}\end{bmatrix}=\begin{bmatrix}1&0&0\\1&1&0\\1&2&1\end{bmatrix}\times\begin{bmatrix}a_{i}\\b_{i}\\c_{i}\end{bmatrix}\),这个同样可以矩阵 ksm 计算。时间复杂度同上。

代码与前一种解法大同小异:

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MOD=1e9+7;
int n,m;
struct mat{
ll a[3][3];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat res;
for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++)
res.a[i][j]+=a[i][k]*rhs.a[k][j];
for(int i=0;i<3;i++) for(int j=0;j<3;j++) res.a[i][j]%=MOD;
return res;
}
};
int main(){
mat x,y,ret;ret.a[0][0]=ret.a[1][0]=ret.a[2][0]=1;
x.a[0][0]=1;x.a[0][1]=0;x.a[0][2]=1;
x.a[1][0]=1;x.a[1][1]=1;x.a[1][2]=1;
x.a[2][0]=1;x.a[2][1]=2;x.a[2][2]=2;
y.a[0][0]=1;y.a[0][1]=0;y.a[0][2]=0;
y.a[1][0]=1;y.a[1][1]=1;y.a[1][2]=0;
y.a[2][0]=1;y.a[2][1]=2;y.a[2][2]=1;
scanf("%d%d",&n,&m);int pre=0;
for(int i=1,v;i<=m;i++){
scanf("%d",&v);int stp=v-pre-1;
mat z=x;for(;stp;stp>>=1,z=z*z) if(stp&1) ret=z*ret;
ret=y*ret;pre=v;
} int stp=n-pre-1;
mat z=x;for(;stp;stp>>=1,z=z*z) if(stp&1) ret=z*ret;
printf("%d\n",ret.a[2][0]);
return 0;
}

Atcoder Grand Contest 013 E - Placing Squares(组合意义转化+矩阵快速幂/代数推导,思维题)的更多相关文章

  1. Atcoder Grand Contest 001E - BBQ Hard(组合意义转化,思维题)

    Atcoder 题面传送门 & 洛谷题面传送门 Yet another 思维题-- 注意到此题 \(n\) 数据范围很大,但是 \(a_i,b_i\) 数据范围很小,这能给我们什么启发呢? 观 ...

  2. AtCoder Grand Contest 013 E - Placing Squares

    题目传送门:https://agc013.contest.atcoder.jp/tasks/agc013_e 题目大意: 给定一个长度为\(n\)的木板,木板上有\(m\)个标记点,距离木板左端点的距 ...

  3. AtCoder Grand Contest 013 C:Ants on a Circle

    题目传送门:https://agc013.contest.atcoder.jp/tasks/agc013_c 题目翻译 给你一个周长为\(L\)的圆,有\(N\)只蚂蚁在圆上爬,速度为一单位距离每秒. ...

  4. AtCoder Grand Contest 013

    这场打得蛮菜的,很晚才出BC,还一堆罚时…… A - Sorted Arrays 题目大意:将给定数列划分成单调不增或单调不减的区间,求最少区间数. 贪心即可. #include<cstdio& ...

  5. AtCoder Grand Contest 013 C :Ants on a Circle

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. AtCoder Grand Contest 013题解

    传送门 \(A\) 先把相同的缩一起,然后贪心就可以了 //quming #include<bits/stdc++.h> #define R register #define fp(i,a ...

  7. 【agc013d】AtCoder Grand Contest 013 D - Piling Up

    题意 盒子里有n块砖,每块的颜色可能为蓝色或红色. 执行m次三步操作: 1.从盒子里随便拿走一块砖 2.放入一块蓝砖和红砖到盒子里 3.从盒子里随便拿走一块砖 给定n,m 问拿出来的砖,可能有多少种不 ...

  8. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  9. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

随机推荐

  1. BUAA2020软工作业(二)——对软件工程的初步理解

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业 我在这个课程的目标是 进一步提高自己的编码能力,工程能力 这个作业在哪个具体方面帮助 ...

  2. 基于docker-compose搭建sonarqube代码质量检测平台

    一.需求 在我们开发的过程中,难免有时候代码写的不规范,或存在一些静态的bug问题,这个时候一个良好的代码检查工具就很有必要,而sonarqube正好可以满足整个要求. 二. docker-compo ...

  3. UVA-1016 Silly Sort

    UVA-1016 题目大意:给定一个长度为n的序列,每次操作可以交换任意两个数的位置,代价为两个数的和,求最小代价,将序列排成有序的. 首先,显然需要交换的数一定会形成环: 那么对于每一个环,我们有两 ...

  4. 零基础学习Linux心得总结

    很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...

  5. 计算机网络之介质访问控制(静态划分信道、FDM、TDM、STDM、WDM、CDM)、(动态划分信道、ALOHA、CSMA、CSMA/CD、CSMA/CA)、令牌传递协议

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/104935912 学习课程:<2019王道考研计算机网络> 学习目的 ...

  6. Hadoop的安装与部署

    一.硬件及环境 服务器:3台,IP分别为:192.168.100.105.192.168.100.110.192.168.100.115 操作系统:Ubuntu Server 18.04 JDK:1. ...

  7. ShardedJedisPipeline 源码分析

    一.什么是pipeline?什么是ShardedJedis? 由于pipeline和ShardedJedis的介绍和源码分析在网上已经有了,本文就不再赘述,直接给出链接: pipeline的介绍: h ...

  8. k8s入坑之路(12)ingress-nginx安装配置四层代理

    ingress官方文档地址:http://docs.kubernetes.org.cn/  https://feisky.gitbooks.io/kubernetes/content/plugins/ ...

  9. 力扣 - 剑指 Offer 30. 包含min函数的栈

    题目 剑指 Offer 30. 包含min函数的栈 思路1 使用一个辅助栈min_stack,用来维护栈的最小的元素 每次添加元素入栈时候,data_stack和min_stack都要同时维护 dat ...

  10. 端口被占用(启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法)

    一.问题描述 在IntelliJ IDEA 中启动Tomcat服务器时就出现了如下图所示的错误: 错误: 代理抛出异常错误**: java.rmi.server.ExportException: Po ...