UOJ#54 BZOJ3434 [WC2014]时空穿梭
题目描述
小 X 驾驶着他的飞船准备穿梭过一个 \(n\) 维空间,这个空间里每个点的坐标可以用 \(n\) 个实数表示,即 \((x_1,x_2,\dots,x_n)\)。
为了穿过这个空间,小 X 需要在这个空间中选取 \(c\)(\(c\geq 2\))个点作为飞船停留的地方,而这些点需要满足以下三个条件:
每个点的每一维坐标均为正整数,且第 \(i\) 维坐标不超过 \(m_i\)。
第 \(i+1\)(\(1\leq i<c\))个点的第 \(j\)(\(1\leq j\leq n\))维坐标必须严格大于第 \(i\) 个点的第 \(j\) 维坐标。
存在一条直线经过所选的所有点。在这个 \(n\) 维空间里,一条直线可以用 \(2n\) 个实数 \(p_1,p_2,\dots,p_n,v_1,v_2,\dots,v_n\) 表示。直线经过点 \((x_1,x_2,\dots,x_n)\),当且仅当存在实数 \(t\),使得对 \(i=1\dots n\) 均满足 \(x_i=p_i+v_it\)。
小 X 还没有确定他的最终方案,请你帮他计算一下一共有多少种不同的方案满足他的要求。由于答案可能会很大,你只需要输出答案 \(mod10007\) 后的值。
输入格式
第一行包含一个正整数 \(T\),表示有 \(T\) 组数据需要求解。
每组数据包含两行,第一行包含两个正整数 \(n,c\)(\(c\geq 2\)),分别表示空间的维数和需要选择的暂停点的个数。
第二行包含 \(n\) 个正整数,依次表示 \(m_1,m_2,…,m_n\)。
输出格式
共 \(T\) 行,每行包含一个非负整数,依次对应每组数据的答案。
样例
input
3
2 3
3 4
3 3
3 4 4
4 4
5 9 7 8
output
2
4
846
explanation
对于第一组数据,共有两种可行的方案:一种选择 \((1,1),(2,2),(3,3)\),另一种选择 \((1,2),(2,3),(3,4)\)。
限制与约定
\]
时间限制: 1s, 空间限制: 512MB.
题解
首先,我们发现只要满足\(x_i < y_i, i = 1,2,\dots,n\) ,(其中\((x_1, x_2,\dots,x_n),(y_1, y_2,\dots,y_n)\)分别是第一个点和最后一个点的坐标)且点的不同排列算同一种即可。
那么,我们枚举这两个点之后,以其为端点的线段上共有(除去两端)\(\gcd(y_1-x_1,y_2-x_2,\dots.y_n-x_n)\)个点。其中选出\(c-2\)个点的方式有\(C_{\gcd(y_1-x_1,y_2-x_2,\dots.y_n-x_n)}^{c-2}\)种,所以总方案数是
\]
我们发现,所有\(p_i=y_i-x_i\)固定之后,方案数恰有
\]
种,这是因为\(p_i\)固定后\(x_i\)只能取\(1,2,\dots,m_i-p_i\).
于是我们有
\]
优先枚举\(d=\gcd(p_1, p_2,\dots,p_n)\)(下式中\(m_{min}\)表示\(\min(m_1,m_2,\dots,m_n)\):
\]
令
\]
则有
\sum_{d\mid l}f(l)&=\sum_{\substack{1\leq q_i < m_i \\ i = 1,2,\dots,n\\d\mid\gcd(p_1, p_2,\dots,p_n)}}\prod_{i=1}^n(m_i-p_i)\\
&=\sum_{\substack{1\leq q_i'd < m_i \\ i = 1,2,\dots,n}}\prod_{i=1}^n(m_i-p_i'd)\\
&=\prod_{i=1}^n\sum_{p'=1}^{\left\lfloor\frac{m_i-1}d\right\rfloor}(m_i-p'd)\\
&=\prod_{i=1}^n\left[m_i\left\lfloor\frac{m_i-1}d\right\rfloor-\frac{d\left\lfloor\frac{m_i-1}d\right\rfloor\left(1+\left\lfloor\frac{m_i-1}d\right\rfloor\right)}2\right]
\end{aligned}\]
最后一步是等差数列求和。
由莫比乌斯反演可知:
\]
于是有
ans&=\sum_{d=1}^{m_{min}-1}C_d^{c-2}\sum_{d\mid l}\mu\left(\frac ld \right)\prod_{i=1}^n\left[m_i\left\lfloor\frac{m_i-1}l\right\rfloor-\frac{l\left\lfloor\frac{m_i-1}l\right\rfloor\left(1+\left\lfloor\frac{m_i-1}l\right\rfloor\right)}2\right]\\
&=\sum_{l=1}^{m_{min}-1}\prod_{i=1}^n\left[m_i\left\lfloor\frac{m_i-1}l\right\rfloor-\frac{l\left\lfloor\frac{m_i-1}l\right\rfloor\left(1+\left\lfloor\frac{m_i-1}l\right\rfloor\right)}2\right]\sum_{d\mid l}\mu\left(\frac ld \right)C_d^{c-2}
\end{aligned}\]
易知\(\prod_{i=1}^n\left[m_i\left\lfloor\frac{m_i-1}l\right\rfloor-\frac{l\left\lfloor\frac{m_i-1}l\right\rfloor\left(1+\left\lfloor\frac{m_i-1}l\right\rfloor\right)}2\right]\)在将所有\(\left\lfloor\frac{m_i-1}l\right\rfloor\)作为常数看待的情况下是一个关于\(l\)的不超过\(n\)次(是因为\(mod10007\)之后有可能次数更低)的多项式,而且引起至少一个\(\left\lfloor\frac{m_i-1}l\right\rfloor\)改变的\(l\)有\(O(n\sqrt m)\)个,于是可以对每一个所有\(\left\lfloor\frac{m_i-1}l\right\rfloor\)都不改变的段分别求和。由于此时它是关于\(l\)的多项式,我们只需预处理出所有的\(S_{c,p,t}=\sum_{l=1}^tl^p\sum_{d\mid l}\mu\left(\frac ld \right)C_d^{c-2}\)即可。至于如何在只改变一个因式时快速维护成绩中各项的系数,可以用线段树实现(代码中为zkw线段树)。
完。
Code
#include <algorithm>
#include <cstdio>
const int N = 12;
const int C = 21;
const int M = 100001;
const int mod = 10007;
int fac[mod], inv[mod];
int mu[M], f[C][M], S[C][M][N];
int p[N * 1000], m[N];
inline int CC(int a, int b) {
if (!b) return 1;
if (a % mod < b % mod) return 0;
return CC(a / mod, b / mod) * fac[a % mod] % mod * inv[fac[b % mod]] % mod * inv[fac[(a - b) % mod]] % mod;
}
int a[64][N], po[64];
int mdp[N];
int n, mm, c;
void upd(int x) {
int l = x * 2, r = x * 2 + 1;
po[x] = po[l] + po[r];
for (int i = 0; i <= po[x]; ++i) a[x][i] = 0;
for (int i = 0; i <= po[l]; ++i)
for (int j = 0; j <= po[r]; ++j)
a[x][i + j] = (a[x][i + j] + a[l][i] * a[r][j] % mod) % mod;
}
int sum(int l, int r) {
int ans = 0;
for (int i = 0; i <= po[1]; ++i)
ans = (ans + a[1][i] * (S[c][r][i] - S[c][l - 1][i]) % mod) % mod;
return ans;
}
int main() {
fac[0] = 1;
for (int i = 1; i < mod; ++i) fac[i] = fac[i - 1] * i % mod;
inv[1] = 1;
for (int i = 2; i < mod; ++i) inv[i] = mod - (mod / i) * inv[mod % i] % mod;
mu[1] = 1;
for (int i = 1; i < M; ++i)
for (int j = i * 2; j < M; j += i)
mu[j] -= mu[i];
for (int c = 2; c < C; ++c) {
for (int i = 1; i < M; ++i)
f[c][i] = 0;
for (int d = c - 1; d < M; ++d) {
int cc = CC(d - 1, c - 2);
for (int i = 1; i * d < M; ++i)
f[c][i * d] = (f[c][i * d] + cc * mu[i]) % mod;
}
for (int j = 0; j < N; ++j)
S[c][0][j] = 0;
for (int i = 1; i < M; ++i)
for (int j = 0, ij = 1; j < N; ++j, ij = ij * (i % mod) % mod)
S[c][i][j] = (S[c][i - 1][j] + f[c][i] * ij) % mod;
}
int T;
scanf("%d", &T);
while (T--) {
mm = 10000000;
scanf("%d%d", &n, &c);
for (int i = 0; i < n; ++i)
scanf("%d", &m[i]), mm = std::min(mm, m[i]);
if (mm < c) {
printf("0\n");
continue;
} if (n == 1) {
printf("%d\n", CC(m[0], c));
continue;
}
int t = 0;
p[t++] = 1;
for (int i = 0; i < n; ++i) {
int last = 1;
while (last < m[i] - 1) {
last = (m[i] - 1) / ((m[i] - 1) / last) + 1;
p[t++] = last;
}
}
std::sort(p, p + t);
t = (int)(std::unique(p, p + t) - p);
p[t] = mm;
int d = 1;
while (d < n) d <<= 1;
for (int i = 0; i < n; ++i) mdp[i] = m[i];
for (int i = 1; i <= d * 2; ++i) a[i][po[i] = 0] = 1;
int ans = 0;
for (int i = 0; p[i] < mm && i < t; ++i) {
int l = p[i], r = p[i + 1] - 1; //[l, r]
for (int j = 0; j < n; ++j)
if ((m[j] - 1) / l != mdp[j]) {
mdp[j] = (m[j] - 1) / l;
int k = d + j;
po[k] = 1;
a[k][0] = m[j] % mod * (mdp[j] % mod) % mod;
a[k][1] = -mdp[j] % mod * ((mdp[j] + 1) % mod) % mod * inv[2] % mod;
while (k /= 2)
upd(k);
}
ans = (ans + sum(l, r)) % mod;
}
printf("%d\n", (ans + mod) % mod);
}
return 0;
}
UOJ#54 BZOJ3434 [WC2014]时空穿梭的更多相关文章
- BZOJ3434 WC2014时空穿梭(莫比乌斯反演)
考虑枚举相邻点距离差的比例.显然应使比例值gcd为1以保证不重复统计.确定比例之后,各维坐标的方案数就可以分开考虑.设比例之和为k,则若坐标上限为m,该维坐标取值方案数即为Σm-ki (i=1~⌊m/ ...
- BZOJ3434 [Wc2014]时空穿梭
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 【BZOJ3434】[Wc2014]时空穿梭 莫比乌斯反演
[BZOJ3434][Wc2014]时空穿梭 Description Input 第一行包含一个正整数T,表示有T组数据求解每组数据包含两行,第一行包含两个正整数N,C(c>=2),分别表示空间 ...
- UOJ 54 【WC2014】时空穿梭——莫比乌斯反演
题目:http://uoj.ac/problem/54 想写20分. Subtask 2 就是枚举4个维度的值的比例,可算对于一个比例有多少个值可以选,然后就是组合数.结果好像不对. 因为模数太小,组 ...
- 【BZOJ】3434: [Wc2014]时空穿梭
http://www.lydsy.com/JudgeOnline/problem.php?id=3434 题意:n维坐标中要找c个点使得c个点在一条线上且每一维的坐标单调递增且不能超过每一维限定的值m ...
- [WC2014]时空穿梭(莫比乌斯反演)
https://www.cnblogs.com/CQzhangyu/p/7891363.html 不难推到$\sum\limits_{D=1}^{m_1}\sum\limits_{d|D}C_{d-1 ...
- BZOJ 3434 [WC2014]时空穿梭 (莫比乌斯反演)
题面:BZOJ传送门 洛谷传送门 好难啊..反演的终极题目 首先,本题的突破口在于直线的性质.不论是几维的空间,两点一定能确定一条直线 选取两个点作为最左下和最右上的点! 假设现在是二维空间,选取了$ ...
- [WC2014]时空穿梭
这才叫莫比乌斯反演题. 一.题目 点此看题 二.解法 也没有什么好的思路,我们不妨把暴力柿子写出来,我们想枚举直线,但是这道题不能枚举直线的斜率,所以就要用整数来表示直线,我们不妨枚举出发点和终止点的 ...
- Vue2 实现时空穿梭框功能模块
前言 这篇文章主要是分享一个时空穿梭框功能,也就是我们平时用的选择功能.勾选了的项就会进入到另一个框中. 时空穿梭框之旅 示例演示: 这个时空穿梭框实现了: 1.可以全选.反选 2.没有选中时,不可以 ...
随机推荐
- Python之机器学习K-means算法实现
一.前言: 今天在宿舍弄了一个下午的代码,总算还好,把这个东西算是熟悉了,还不算是力竭,只算是知道了怎么回事.今天就给大家分享一下我的代码.代码可以运行,运行的Python环境是Python3.6以上 ...
- leetcode-482-License Key Formatting
题目描述: You are given a license key represented as a string S which consists only alphanumeric charact ...
- WampServer访问出现403forbidden的问题解决
1,软件装上以后出现所有服务运行,80端口未被占用的情况下服务器一直处于离线状态 解决方案如下: 网络上面很多教程多说切换服务器为在线状态即可,但是我发现我的菜单里面并没有,用命令又嫌麻烦 在图表上面 ...
- 【转载】MSDN-MDX#001 - 多维表达式 (MDX) 参考
摘录于MSDN MDX 的一些重要概念 1. MDX 介绍 多维表达式 (MDX) 是用于在 Microsoft SQL Server Analysis Services (SSAS) 中处理和检索多 ...
- iterm自动登录ssh脚本
经常在工作中需要切换到不同的服务器去部署,或者查看日志,每次登录都要去找对应的IP和地址,非常麻烦,最终决定使用iterm2+脚本来实现自动登录. 1.iterm2(下载安装不再介绍http://ww ...
- (转)[小工具] Linux下列格式化工具 - column
当你看到Linux下命令输出的列歪歪扭扭时,是不是看着很不爽?column 命令就可以方便地解决这个问题. 比如: 我们一般就只用到上面这一个用法. column的其他用法如下: 选项 含义 -c 字 ...
- ACM练习网站
1.http://www.acmerblog.com/ Acm之家 2.http://acm.nyist.net/JudgeOnline/problemset.php 南阳理工学院
- Linux安装phpMywind
1.安装MySQL http://www.cnblogs.com/wangshuyi/p/6091244.html 2.安装apache.php.及其扩展 yum install -y httpd p ...
- 002javascript变量&数据类型
•变量 –JavaScript 是一种弱类型的脚本语言 –var c = 3:即变量的声明(变量使用之前必须加var声明,编程规范) –变量的命名规则! •1.变量命名必须以字母或是下标符号”_”或者 ...
- Microsoft Power BI Desktop概念学习系列之Microsoft Power BI Desktop的下载和安装(图文详解)
不多说,直接上干货! 官网 https://powerbi.microsoft.com/zh-cn/downloads/ 这里,一般用126邮箱. 因为对于163这样的邮箱是不行. 欢迎大家,加入我的 ...