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. 《看漫画学Pyhton》中计算水仙花数

    利用while循环实现 i = 100 r = 0 s = 0 t = 0 while i < 1000: r = i // 100 s = (i - r * 100) // 10 t = i ...

  2. 【UE4 C++】Slate 初探: Editor UI 与 Game UI

    概述 名词区分 Slate Slate 是完全自定义.与平台无关的UI框架 应用 可用于编辑器UI,编辑器的大部分界面都是使用 Slate 构建的 可做为游戏UI 可作为独立应用开发 只能 C++ 开 ...

  3. The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session-ConcurrentHashMap使用在webSocket中采的坑

    一.问题由来 现在开发的一个项目中使用webSocket这个技术和Unity客户端程序进行联动操作,因为socket连接相对来说比http请求连接更加的快速,而且是 一个长链接,方便于这个项目进行其他 ...

  4. 6月2日 Scrum Meeting

    日期:2021年6月2日 会议主要内容概述: 取消账单类别自定义 图表属性分析取消函数输入 增加新的主题模板 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇 ...

  5. mac上安装lua

    一.背景 最近在操作redis的时候,有些时候是需要原子操作的,而redis中支持lua脚本,因此为了以后学习lua,此处记录一下 lua的安装. 二.mac上安装lua 其余的系统上安装lua步骤大 ...

  6. EFCore_环境搭建与简单使用_01

    开发环境搭建 经典步骤:建实体类.建DbContext.生成数据库 本次使用codefirst模式,走下流程,(你也可以先建好数据库,用命令行的形式,直接生成DbContext,而且生成的DbCont ...

  7. 电路维修(双端队列 & 最短路)

    达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上. 翰翰的家里有一辆飞行车. 有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板的整体结构是一个$ ...

  8. JAVA笔记10__Math类、Random类、Arrays类/日期操作类/对象比较器/对象的克隆/二叉树

    /** * Math类.Random类.Arrays类:具体查JAVA手册...... */ public class Main { public static void main(String[] ...

  9. poj 1129 Channel Allocation(图着色,DFS)

    题意: N个中继站,相邻的中继站频道不得相同,问最少需要几个频道. 输入输出: Sample Input 2 A: B: 4 A:BC B:ACD C:ABD D:BC 4 A:BCD B:ACD C ...

  10. CSS 盒子的边距塌陷

    tip:为能更直观地学习,本文章已省略部分 css 样式代码. 我相信下面的情形大家在日常工作中常常碰到:在制作静态页面中,为了页面整体的协调与美观,我们想让子盒子 image-div 的上边沿距离父 ...