CS Academy Gcd on a Circle(dp + 线段树)
题意
给你一个长为 \(n\) 的环,你可以把它断成任意 \(k\) 段 \((1 < k \le n)\) ,使得每一段的 \(\gcd\) 都 \(>1\) 。
问总共有多少种方案,对于 \(10^9 + 7\) 取模。
\(n \le 10^5, 2 \le a_i \le 10^9\) 。
题解
首先我们考虑序列上怎么做。
我们令 \(dp_i\) 为到 \(i\) 这个点的方案数, \(pre_i\) 为 \(i\) 向前延伸最长的那个点满足 \((\displaystyle \gcd_{j = pre_i}^{i} a[j]) > 1\) 。
那么
\]
显然这个 \(dp\) 可以用前缀和来进行优化成 \(O(n)\) 的。
至于 \(pre_i\) 的处理可以用线段树求区间 \(\gcd\) ,然后用 two-pointers 来扫端点就行了,是 \(O(n( \log n + \log V))\) 的( \(\displaystyle V = \max_{i=1}^{n} a_i\) )。
好像利用 \(\gcd\) 的一些奇怪势能分析可以证明。
然后如果成环的话,我们只需要多考虑一种情况也就是 \(1,n\) 相连。
对于这种情况,可以考虑枚举最后面有 \(k\) 个数和 \(n\) 相连就行了。
然后每次计算的时候,可以类似于前面 \(dp\) 的计算就行了,但是要注意一下,那个 \([pre_i = 1]\) 要转化成后面 \(k\) 个数与前缀的 \(\gcd\) 是否 \(>1\) 。(也就是我们强行把后 \(k\) 个数当做一个整体提到前面就行了)
然后这样直接做是 \((n^2 \log V)\) 的,不够优秀。
但是我们发现很多数其实没有什么本质区别的,也就是后缀 \(\gcd\) 相同的一部分点可以一起计算。
这样的话,我们可以只在 \(\gcd\) 转折处,以及 \(0\) 号点计算就行了(因为要考虑上 \(1\) 向后那一片 \(\gcd\) 相同的数)。然后复杂度就是 \(O(n \log^2 V)\) 的了。
因为一个点向一端不断延伸,它的 \(\gcd\) 变换次数是 \(O(\log V)\) 的,因为每次变化至少会对于其中一个指数 \(-1\) 。
还有个特殊情况,也就是全部 \(\gcd > 1\) 的情况,需要将方案数 \(- (n - 1)\) 。(因为至少要分成 \(1\) 段)
最后就是 \(O(n (\log n + \log V) \log V)\) 的。
总结
对于一类划分环计数的题目,可以考虑枚举最后面那一段和前面相连的长度,然后直接一遍 \(O(n)\) 计数。
对于有些关于 \(\gcd\) 的题可以利用 \(\gcd\) 变换次数不超过 \(O(\log V)\) 来做。
代码
代码还是很好写的,可以参考一下。(其实博主参考了一下 ysgs 大佬的代码 )
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("gcd-on-a-circle.in", "r", stdin);
freopen ("gcd-on-a-circle.out", "w", stdout);
#endif
}
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
const int N = 1e5 + 1e3, Mod = 1e9 + 7;
int a[N];
struct Segment_Tree {
int Gcd[N << 2];
void Build(int o, int l, int r) {
if (l == r) { Gcd[o] = a[l]; return ; }
int mid = (l + r) >> 1;
Build(lson); Build(rson); Gcd[o] = __gcd(Gcd[o << 1], Gcd[o << 1 | 1]);
}
int Query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return Gcd[o];
int mid = (l + r) >> 1;
if (qr <= mid) return Query(lson, ql, qr);
if (ql > mid) return Query(rson, ql, qr);
return __gcd(Query(lson, ql, qr), Query(rson, ql, qr));
}
} T;
inline int Add(int a, int b) { return (a += b) >= Mod ? a - Mod : a; }
int n, sum[N], dp[N], pre[N];
void Calc(int cur) {
sum[0] = 1;
For (i, 1, n) {
cur = __gcd(cur, a[i]);
if (cur > 1) dp[i] = sum[i - 1];
else dp[i] = Add(sum[i - 1], Mod - sum[max(0, pre[i] - 2)]);
sum[i] = Add(sum[i - 1], dp[i]);
}
}
int main () {
File();
n = read();
For (i, 1, n) a[i] = read(); T.Build(1, 1, n);
pre[1] = 1;
For (i, 2, n)
for (pre[i] = pre[i - 1]; pre[i] < i; ++ pre[i])
if (T.Query(1, 1, n, pre[i], i) > 1) break;
int Last = n, suf = 0, cur, ans = 0;
Fordown (i, n, 1) {
cur = __gcd(a[i], suf);
if (cur != suf || i == 1) {
Calc(suf); ans = Add(ans, Add(sum[Last], Mod - sum[i - 1]));
Last = i - 1; suf = cur;
}
}
printf ("%d\n", Add(ans, (Mod - (T.Gcd[1] > 1 ? (n - 1) : 0))));
return 0;
}
CS Academy Gcd on a Circle(dp + 线段树)的更多相关文章
- ZOJ 3349 Special Subsequence 简单DP + 线段树
同 HDU 2836 只不过改成了求最长子串. DP+线段树单点修改+区间查最值. #include <cstdio> #include <cstring> #include ...
- hdu 3016 dp+线段树
Man Down Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- cf834D(dp+线段树区间最值,区间更新)
题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...
- Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)
Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树) 题目链接 题意 给定一个nm的矩阵,每行取2k的矩阵,求总 ...
- POJ1769 Minimizing maximizer(DP + 线段树)
题目大概就是要,给一个由若干区间[Si,Ti]组成的序列,求最小长度的子序列,使这个子序列覆盖1到n这n个点. dp[i]表示从第0个到第i个区间且使用第i个区间,覆盖1到Ti所需的最少长度 对于Si ...
- [USACO2005][POJ3171]Cleaning Shifts(DP+线段树优化)
题目:http://poj.org/problem?id=3171 题意:给你n个区间[a,b],每个区间都有一个费用c,要你用最小的费用覆盖区间[M,E] 分析:经典的区间覆盖问题,百度可以搜到这个 ...
- POJ 3162 Walking Race 树形DP+线段树
给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...
- 【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机
这题我的代码在hdu上AC,在uva上WA. 题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串.问d值的和最大是多少. (1≤n≤2×10^4 ,串的总长度< ...
- bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄 ...
随机推荐
- jQuery实现Ajax请求时,页面显示等待的效果,超过指定请求时间后,进行其他操作
背景:有一个按钮,点击之后向后端程序发起Ajax请求,在请求结果没有返回之前,页面显示等待的效果,此时仍旧是异步请求,等待的效果在接收到结果后撤销. 需求:因为网络延迟或者后端程序的问题,在发起Aja ...
- Ubuntu端口开放
一.关于iptable的介绍 维基百科:https://zh.wikipedia.org/wiki/Iptables 注意:iptables的操作需要root权限 二.具体操作 sudo apt-ge ...
- mysql-SQL Error: 1205, SQLState: 41000
mysql-SQL Error: 1205, SQLState: 41000——CSDN问答频道https://ask.csdn.net/questions/176492 mysql-SQL Erro ...
- vs快捷键 C#
快速构建构造函数 输入 ctor 然后按 TAB 键 快速构建自动属性 在变量那里,右击鼠标,点“重构”--“封装字段” Visual Studio快捷键 [VS2008/VS2005] ****** ...
- MySQL数据库性能优化思路与解决方法(一转)
1.选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越 小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设 ...
- windows中dir命令
最近想用dos命令打印指定目录下的所有文件夹的完整路径.最终发现可用dir命令来实现.在此学习下dir的各项命令. 32位win7系统上,打印帮助文档. D:\test>dir /? 显示目录中 ...
- sql之cursor的简介和字符串拆分(split)与游标的使用
字符串拆分(split)与游标的使用 CREATE TABLE Plates ( ,), ) NOT NULL, [BusinessId] INT NOT NULL, ) ),),), SELECT ...
- Oracle 用户管理与权限分配
用户管理是系统管理员最基本的任务之一,用户想要连接数据库并且使用相应的系统资源就必须是系统的合法用户且具有对应的权限. 1 创建用户 default tablespace default_tables ...
- Java中有关Null的9件事(转)
对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...
- [转帖] SS, SP, BP 三个寄存器
SS, SP, BP 三个寄存器 https://blog.csdn.net/vspiders/article/details/55669265 这么看 计算机组成原理 还有 考试的很多题目非常有用啊 ...