【AGC009C】Division into Two

题面

洛谷

题解

首先有一个比较显然的\(n^2\)算法:

设\(f_{i,j}\)表示\(A\)序列当前在第\(i\)个,\(B\)序列当前在第\(j\)个的方案数,发现\(i,j\)大小没有限制不是很好转移,于是再设一个\(g_{i,j}\)表示\(B\)序列当前在第\(i\)个,\(A\)序列当前在第\(j\)个的方案数的,这样子我们就可以钦定\(i>j\)了,转移会方便许多。

转移如下:

\[\left\{
\begin{aligned}
f_{i+1,j}\leftarrow f_{i,j}(a_{i+1}-a_i\geq A)\\
g_{i+1,i}\leftarrow f_{i,j}(a_{i+1}-a_j\geq B)\\
g_{i+1,j}\leftarrow g_{i,j}(a_{i+1}-a_i\geq B)\\
f_{i+1,i}\leftarrow g_{i,j}(a_{i+1}-a_j\geq A)
\end{aligned}
\right.
\]


然后让我们想一想怎么优化这个东西。

不妨设\(A<B\),则对于\(\forall i\geq 3,a_i-a_{i-2}\geq A\),对于不符合的我们直接判掉。

设\(f_i\)表示当前\(B\)序列在\(i\)的方案数,我们对于可以转移过来的\(j\),必须要满足\(a_i-a_j\geq B\),而对于\(\forall k\in [j+1,i-1]\),则要满足\(a_k-a_{k-1}\geq A\),考虑到这样的\(j\)是一个区间,而区间左右端点单调,我们把这个区间搞出来然后前缀和优化即可。

复杂度\(O(n)\)。

代码

\\O(n^2)
int main () {
scanf("%d %lld %lld", &N, &A, &B);
if (A > B) swap(A, B);
for (int i = 1; i <= N; i++) scanf("%lld", a + i);
for (int i = 3; i <= N; i++) if (a[i] - a[i - 2] < A) return puts("0") & 0;
a[0] = -1e18;
int ans = 0;
f[1][0] = 1, g[1][0] = 1;
for (int i = 1; i <= N; i++)
for (int j = 0; j < i; j++) {
if (a[i + 1] - a[i] >= A) f[i + 1][j] = (f[i + 1][j] + f[i][j]) % Mod;
if (a[i + 1] - a[j] >= B) g[i + 1][i] = (g[i + 1][i] + f[i][j]) % Mod;
if (a[i + 1] - a[i] >= B) g[i + 1][j] = (g[i + 1][j] + g[i][j]) % Mod;
if (a[i + 1] - a[j] >= A) f[i + 1][i] = (f[i + 1][i] + g[i][j]) % Mod;
}
for (int i = 0; i < N; i++) ans = (ans + (f[N][i] + g[N][i]) % Mod) % Mod;
printf("%d\n", ans);
return 0;
}
\\O(n)
int main () {
scanf("%d %lld %lld", &N, &A, &B);
for (int i = 1; i <= N; i++) scanf("%lld", a + i);
if (A > B) swap(A, B);
for (int i = 3; i <= N; i++) if (a[i] - a[i - 2] < A) return puts("0") & 0;
f[0] = s[0] = 1;
int l = 0, r = 0;
for (int i = 1; i <= N; i++) {
while (r < i - 1 && a[i] - a[r + 1] >= B) ++r;
if (l <= r) f[i] = (s[r] - (l ? s[l - 1] : 0) + Mod) % Mod;
s[i] = (s[i - 1] + f[i]) % Mod;
if (i != 1 && a[i] - a[i - 1] < A) l = i - 1;
}
int ans = 0;
for (int i = N; ~i; i--) {
ans = (ans + f[i]) % Mod;
if (i != N && a[i + 1] - a[i] < A) break;
}
printf("%d\n", ans);
return 0;
}

最新文章

  1. js拖拽原理和碰撞原理
  2. Android Studio连接真机没反应?
  3. cocoaPod相关问题
  4. POJ 3308 Paratroopers (对数转换+最小点权覆盖)
  5. Roy Li的学习和成长自传
  6. iOS 中使用.9图
  7. linux进程间通信--有名管道
  8. 从相对路径说开来(从C++到Qt)
  9. oracle导入
  10. HDU 4303 Hourai Jeweled 树dp 所有权利和航点 dfs2次要
  11. Devexpress XtraReports 交叉报表
  12. poi 合并单元格、设置边框
  13. 读阮一峰对《javascript语言精粹》的笔记,我有疑问。
  14. 转账示例(四):service层面实现(线程管理Connection,AOP思想,动态代理)(本例采用QueryRunner来执行sql语句,数据源为C3P0)
  15. vue的表单编辑删除,保存取消功能
  16. 【DFS】困难的串
  17. Perl的IO操作(2):更多文件句柄模式
  18. Orchard详解--第八篇 拓展模块及引用的预处理
  19. Servlet(六):连接数据库,完整的CRUD
  20. Linux基础命令 ls

热门文章

  1. POJ 1306 暴力求组合数
  2. 使用Jenkins来实现内部的持续集成流程(下)
  3. 使用Ueditor上传图片到图片服务器(一)
  4. dotnet core 之 gRPC
  5. 数据库xp_cmdshell使用
  6. 深入理解Session和Cookie的区别
  7. SpringMVC数组参数
  8. AD活动目录操作软件设计节选
  9. Flutter 徐徐图之(一)—— 从搭建开发环境到 Hello World
  10. 使用Git Flow规范!