AGC013E
模型转化题,转化不出来就白给。
可以把题目的条件翻译成以下组合语言:
- 有一排 n 个格子,你要在其中插入若干个隔板将其隔成若干段
- 有 m 个特殊格子 a1,a2,…,am,∀i∈[1,m] 你禁止在 ai 与 ai+1 之间放隔板
- 在相邻隔板之间的格子中需恰好放上两个不同的球(可以重合)
不难发现,上述题面中的”隔板“对应原题中的正方形边界,对于一段长度为 l 的段,在上面放两个不同的球的方案数为 l2,也就对应了原题面中的”平方“,而原题中的乘法在上述题面中被翻译成了乘法原理。因此我们就将这题与组合意义联系在了一起。
设 fi,j 表示现在考虑了前 i 个位置,在当前位置到上一个隔板的区间中放上了 j 个球的方案数,其中 j∈[0,2]。
对于非特殊格子 i 我们有状态转移方程:
- fi+1,0=fi,0+fi,2
- fi+1,1=(2fi,0+fi+1,1)+2fi,2
- fi+1,2=(fi,0+fi,1+fi,2)+fi,2
注意这里将不放隔板的转移都放在了前面,放隔板的转移都放在了后面。
对于特殊格子的话状态转移方程只要把放隔板的转移去掉就行了。
不难发现这可以写成矩阵形式。
时间复杂度 O(mlognω3),其中 ω=3。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int n, m;
struct mat {
int a[3][3];
mat (){}
void clear() { memset(a, 0, sizeof a); }
void init() { clear(); for (int i = 0; i < 3; ++i) a[i][i] = 1; }
mat operator * (const mat &x) const {
mat res; res.clear();
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] = (res.a[i][j] + 1ll * a[i][k] * x.a[k][j] % mod) % mod;
return res;
}
} f, x, y;
mat qpow(mat x, int y) {
mat res; res.init();
while (y) {
if (y & 1) res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
int main() {
f.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 lst = -1;
for (int i = 1, cur; i <= m; ++i) {
scanf("%d", &cur);
f = qpow(x, cur - lst - 1) * f, f = y * f, lst = cur;
}
f = qpow(x, n - lst - 1) * f;
printf("%d", f.a[2][0]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话