Die Siedler

题目链接:ARC112F

题目大意

有 n 种牌,2i 个第 i 种牌可以变成一个第 i+1 种牌。
特别的 2n 个第 n 种牌会变成一个第 1 种牌。
然后有 m 种牌包,里面每种牌都有一定的数量,然后牌包数量无限,随便你用。
然后告诉你你一开始有的牌,你可以随意用牌随便变牌,问你手上多少会有多少牌。

思路

考虑到我们肯定是能换就换,因为一定会让牌数变少。
那我们考虑全部不换,甚至退回去,我们就看全部退回成第一种牌,有多少张。

对原来有的牌转化得到数量 RRR,每个卡包也转化得到 bib_ibi​。
那首先会发现一个特别的就是从 nnn 转化到 111,发现少了 2nn!−12^nn!-12nn!−1。
那最后牌数我们可以表示成这个:
v=R+∑i=1mbixi−y(2nn!−1)v=R+\sum\limits_{i=1}^mb_ix_i-y(2^nn!-1)v=R+i=1∑m​bi​xi​−y(2nn!−1)
其中 xi,yx_i,yxi​,y 是让你选的。

v−R=∑i=1mbixi−y(2nn!−1)v-R=\sum\limits_{i=1}^mb_ix_i-y(2^nn!-1)v−R=i=1∑m​bi​xi​−y(2nn!−1)
然后通过斐蜀定理,我们有 v−Rv-Rv−R 得是 gcd⁡(b1,b2,...,bm,2nn!−1)\gcd(b_1,b_2,...,b_m,2^nn!-1)gcd(b1​,b2​,...,bm​,2nn!−1) 的倍数。

那假设上面 gcd⁡\gcdgcd 的结果是 ddd。
考虑根号分治:

d>2nn!d>\sqrt{2^nn!}d>2nn!​
那这个时候我们可以试着暴力枚举倍数,然后直接转换会序列,算出答案。

d⩽2nn!d\leqslant\sqrt{2^nn!}d⩽2nn!​
这个时候我们可以试着用 fif_ifi​ 表示价值为 iii 的最小换成的牌数。
然后转移是 f(i+2k−1(k−1)!)modd=min⁡(f(i+2k−1(k−1)!)modd,fi+1)f_{(i+2^{k-1}(k-1)!)\bmod d}=\min(f_{(i+2^{k-1}(k-1)!)\bmod d},f_i+1)f(i+2k−1(k−1)!)modd​=min(f(i+2k−1(k−1)!)modd​,fi​+1)
然后初始化是 f2k−1(k−1)!modd=1f_{2^{k-1}(k-1)!\bmod d}=1f2k−1(k−1)!modd​=1,这个因为每次都是 +1+1+1 我们可以 bfs 出结果,然后要的就是 fRmoddf_{R\bmod d}fRmodd​

时间复杂度都是:
O(2nn!n)O(\sqrt{2^nn!}n)O(2nn!​n)

发现好像复杂度是 1e91e91e9 级别的。

但是呢,你发现 2nn!−12^nn!-12nn!−1 这个数,它的质因子,比较的有特点。
(因为这个数是固定有的,而且只有 161616 种情况)

看质因子可以点我

发现要么很大(这个大是贴近 2nn!2^nn!2nn! 不是 21616!2^{16}16!21616!),要么很小。
会发现最大的 ddd 大概在 1e61e61e6 的级别上,所以是可以过的。

代码

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#define ll long longusing namespace std;const int N = 17;
const int M = 51;
const int B = 5e6 + 1000;
int n, m, a[N], ans, f[B];
ll R, b[M], n2n, GCD, jc[N];
bool in[B];
queue <int> q;ll change() {ll re = 0, sum = 1;for (int i = 1; i <= n; i++) {re += (1ll << i - 1) * jc[i - 1] * a[i];}return re;
}int back(ll x) {int re = 0;for (int i = 1; i <= n; i++) {re += x % (2 * i); x /= 2 * i;}return re;
}ll gcd(ll x, ll y) {if (!y) return x;return gcd(y, x % y);
}void bfs() {while (!q.empty()) {int now = q.front(); q.pop();for (int i = 1; i <= n; i++) {int to = (now + (1ll << i - 1) * jc[i - 1]) % GCD;if (f[to] > f[now] + 1) {f[to] = f[now] + 1;if (!in[to]) {in[to] = 1; q.push(to);}}}}
}int main() {scanf("%d %d", &n, &m);jc[0] = 1; for (int i = 1; i <= n; i++) jc[i] = jc[i - 1] * i;for (int i = 1; i <= n; i++) scanf("%d", &a[i]); R = change();for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) scanf("%d", &a[j]); b[i] = change();}if (!R) {printf("0"); return 0;}n2n = (1ll << n) * jc[n];GCD = n2n - 1; for (int i = 1; i <= m; i++) GCD = gcd(GCD, b[i]);ans = 2e9;if (GCD <= sqrt(n2n)) {memset(f, 0x7f, sizeof(f));for (int i = 1; i <= n; i++) {int k = (1ll << i - 1) * jc[i - 1] % GCD;f[k] = 1; in[k] = 1; q.push(k);}bfs();ans = f[R % GCD];}else {for (ll val = R % GCD; val < n2n; val += GCD) {if (!val) continue;ans = min(ans, back(val));}}printf("%d\n", ans);return 0;
}

【ARC112F】Die Siedler(根号分治)(bfs)相关推荐

  1. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

  2. [CF587F]Duff is Mad[AC自动机+根号分治+分块]

    题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...

  3. Codeforces Round #507 (Div. 1) D. You Are Given a Tree 根号分治 + dp

    传送门 题意: 有一颗nnn个节点的树,其中一个简单路径集合被称为kkk合法当且仅当: 树的每个节点至多属于一条路径,且每条路径恰好包含kkk个点. 对于k∈[1,n]k\in [1,n]k∈[1,n ...

  4. 【CTSC2010】珠宝商【后缀自动机】【点分治】【根号分治】

    题意:给一棵 nnn 个点的树,每个点有个字符,另给一个长度为 mmm 的特征串,求树上 n2n^2n2 条有向路径在特征串中出现的次数之和. n,m≤5×104n,m\leq 5\times 10^ ...

  5. 【UOJ549】序列妙妙值【异或】【根号分治】

    题意:给一个长度为nnn的序列aaa,将其分成kkk段,不能为空,求所有段的异或和之和的最小值. n≤6×104,ai<216,k≤8n\leq 6\times 10^4,a_i <2^{ ...

  6. 基站建设(三元环计数+根号分治 / bitset)

    基站建设 problem solution code problem 给定 nnn 个地点,以及每个地点的可靠度 RiR_iRi​. 有 mmm 条光纤架,每一条连接两个不同的地点,且是双向的. 测试 ...

  7. CF1039E-Summer Oenothera Exhibition【LCT,根号分治】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1039E 题目大意 给出nnn个数的序列,mmm次询问至少将这个序列分成多少段才能满足每一段的和不超过w−qiw ...

  8. CF1039D-You Are Given a Tree【根号分治,贪心】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1039D 题目大意 给出nnn个点的一棵树,然后对于k∈[1,n]k\in[1,n]k∈[1,n]求每次使用一条 ...

  9. CF587F-Duff is Mad【AC自动机,根号分治】

    正题 题目链接:https://www.luogu.com.cn/problem/CF587F 题目大意 给出nnn个字符串sss.qqq次询问给出l,r,kl,r,kl,r,k要求输出sl..rs_ ...

  10. UOJ#33-[UR #2]树上GCD【长链剖分,根号分治】

    正题 题目链接:https://uoj.ac/problem/33 题目大意 给出nnn个点的一棵树 定义f(x,y)=gcd(dis(x,lca),dis(y,lca))f(x,y)=gcd(\ d ...

最新文章

  1. php 网络请求 get请求和post请求
  2. 01.几张图轻松理解String.intern()
  3. linux的mysql服务器密码忘了,怎么解决?
  4. 如何在 Linux 中启用 Shell 脚本的调试模式
  5. 9个元素换6次达到排序序列_十大算法排序(Sorting Algorithm) Study notes
  6. 关于着色器LinearGradient的使用
  7. linux之用xargs删除这个目录下面后缀为txt的文件(包括子目录)
  8. linux正向连接shell_[经验] Linux 怎么连接 Xshell?
  9. python代码变成运行程序_python脚本转化单个exe执行程序
  10. 大数据(2)---Hadoop由哪几部分组成?
  11. wps启用编辑按钮在哪里_WPS 新功能上线,官宣首发!人人都会用的图片设计
  12. linux基础命令---bzip2
  13. redis数据类型之List
  14. nmap扫描主机存活情况
  15. chm之已取消到该网页的导航解决办法
  16. 高德地图广告投放的优势、效果!
  17. python线性回归实例 x轴坐标相同_python深度学习-tensorflow实现一个线性回归的案例...
  18. 干支纪年法简便算法_初中阶段常用的四种历史纪年法
  19. iphone描述文件
  20. Kinetics400/600/700数据集免费下载

热门文章

  1. 从苏宁电器到卡巴斯基(第二部)第08篇:我在卡巴的日子 VIII
  2. 卡方检验以及P值的计算
  3. linux ext3 fsck一定要慎用
  4. 新建word文件时出现页眉横线
  5. 小福利,杨格(Young)不等式验证之用python里面的matplotlib和numpy模块画图
  6. JAVA之父,詹姆斯·高斯林传奇人生
  7. linux怎么创建swap分区,linux下创建swap分区
  8. 一级标题居中,二级标题固定缩进
  9. 自动生成编号的存储过程
  10. Deepin 20版 安装教程(Vmware)