【ARC112F】Die Siedler(根号分治)(bfs)
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∑mbixi−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∑mbixi−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)相关推荐
- 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries
题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...
- [CF587F]Duff is Mad[AC自动机+根号分治+分块]
题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...
- 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 ...
- 【CTSC2010】珠宝商【后缀自动机】【点分治】【根号分治】
题意:给一棵 nnn 个点的树,每个点有个字符,另给一个长度为 mmm 的特征串,求树上 n2n^2n2 条有向路径在特征串中出现的次数之和. n,m≤5×104n,m\leq 5\times 10^ ...
- 【UOJ549】序列妙妙值【异或】【根号分治】
题意:给一个长度为nnn的序列aaa,将其分成kkk段,不能为空,求所有段的异或和之和的最小值. n≤6×104,ai<216,k≤8n\leq 6\times 10^4,a_i <2^{ ...
- 基站建设(三元环计数+根号分治 / bitset)
基站建设 problem solution code problem 给定 nnn 个地点,以及每个地点的可靠度 RiR_iRi. 有 mmm 条光纤架,每一条连接两个不同的地点,且是双向的. 测试 ...
- CF1039E-Summer Oenothera Exhibition【LCT,根号分治】
正题 题目链接:https://www.luogu.com.cn/problem/CF1039E 题目大意 给出nnn个数的序列,mmm次询问至少将这个序列分成多少段才能满足每一段的和不超过w−qiw ...
- CF1039D-You Are Given a Tree【根号分治,贪心】
正题 题目链接:https://www.luogu.com.cn/problem/CF1039D 题目大意 给出nnn个点的一棵树,然后对于k∈[1,n]k\in[1,n]k∈[1,n]求每次使用一条 ...
- CF587F-Duff is Mad【AC自动机,根号分治】
正题 题目链接:https://www.luogu.com.cn/problem/CF587F 题目大意 给出nnn个字符串sss.qqq次询问给出l,r,kl,r,kl,r,k要求输出sl..rs_ ...
- 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 ...
最新文章
- php 网络请求 get请求和post请求
- 01.几张图轻松理解String.intern()
- linux的mysql服务器密码忘了,怎么解决?
- 如何在 Linux 中启用 Shell 脚本的调试模式
- 9个元素换6次达到排序序列_十大算法排序(Sorting Algorithm) Study notes
- 关于着色器LinearGradient的使用
- linux之用xargs删除这个目录下面后缀为txt的文件(包括子目录)
- linux正向连接shell_[经验] Linux 怎么连接 Xshell?
- python代码变成运行程序_python脚本转化单个exe执行程序
- 大数据(2)---Hadoop由哪几部分组成?
- wps启用编辑按钮在哪里_WPS 新功能上线,官宣首发!人人都会用的图片设计
- linux基础命令---bzip2
- redis数据类型之List
- nmap扫描主机存活情况
- chm之已取消到该网页的导航解决办法
- 高德地图广告投放的优势、效果!
- python线性回归实例 x轴坐标相同_python深度学习-tensorflow实现一个线性回归的案例...
- 干支纪年法简便算法_初中阶段常用的四种历史纪年法
- iphone描述文件
- Kinetics400/600/700数据集免费下载