Flatten

给定\(n\)个正整数\(a_i\),,现在让你求出\(n\)个整数\(b_i\),使得任取\(1\le i < j \le n\),\(a_ib_i=a_jb_j\)始终成立,请你求出\(\sum b_i\)的最小值,答案对\(1e9+7\)取模

\(1\le n \le 10^4\)

\(1 \le a_i \le 10^6\)

题解:最大公倍数取模 + 质因数分解 + 快速幂求乘法逆元

  • 容易得到\(a_ib_i = lcm(\sum a_i)\),那么我们现在只要求出\(n\)个\(a_i\)的最大公倍数\(lcm\)且对\(1e9+7\)取模的结果,答案即为
\[\sum_{i=1}^{n}\frac{lcm}{a_i}
\]
  • 答案中存在除法,但是取模中没有除法,所以我们需要利用快速幂求出\(a_i\)在模\(1e9+7\)下的乘法逆元\(a_i^{-1}\),答案为
\[\sum_{i=1}^{n}lcm*a_i^{-1}
\]
  • 现在我们还需要解决最大公倍数取模的问题:

我们对每个\(a_i\)进行质因子分解,取每个质因子中的最大幂次作为最大公倍数的对应质因子的幂次,然后利用快速幂求出最大公倍数对\(1e9+7\)取模的结果

  • 时间复杂度:质因子分解\(O(\sqrt a_i)\),一共\(n\)个数,\(O(n\sqrt a_i)\),最终时间复杂度为\(O(n\sqrt a_i + nlog(1e9))\)
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10; int n;
int a[N];
int p[N], idx;
bool vis[N];
unordered_map<int, int> mp2; int qpow(int a, int b, int p)
{
int res = 1;
while (b)
{
if (b & 1)
res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res % p;
} void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
int t = a[i];
unordered_map<int, int> mp;
for (int j = 2; j <= t / j; ++j)
{
while (t % j == 0)
{
mp[j]++;
mp2[j] = max(mp2[j], mp[j]);
t /= j;
}
}
if (t > 1)
{
mp[t]++;
mp2[t] = max(mp2[t], mp[t]);
}
}
int d = 1;
for (auto [x, y] : mp2)
{
d = d * qpow(x, y, mod) % mod;
}
int ans = 0;
for (int i = 1; i <= n; ++i)
ans = (ans % mod + (d % mod * qpow(a[i], mod - 2, mod)) % mod) % mod;
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

Tree and Constraints

给你一颗有\(n\)个节点的树,你要给这棵树黑白染色,并且符合\(m\)条限制,每条限制给定\(u\)和\(v\),需要满足\(u\)到\(v\)的路径上至少有一个黑色边,问有多少种染色方案

\(2≤n≤50\)

\(1≤m≤min(20,2n(n−1))\)

题解:容斥原理 + 状压 + 树上异或 \(O(2^mm)\)

  • 首先染色总方案数\(S\)为\(2^{n-1}\),设\(A_i\)为满足第\(i\)个限制条件的合法方案数,题目想让我们求出\(\bigcap_{i=1}^{m}A_i\),即所有限制条件合法方案数的交集,但是比较难求,正难则反,我们不妨从反面考虑该答案:

设\(\bar{A_i}\)为不满足第\(i\)个限制条件的不合法方案数,那么我们把题目想让我们求的答案可以转化为

\[S-\bigcup_{i-1}^{m}\bar{A_i}
\]

因为\(m\le 20\),容易发现我们可以利用容斥原理求出\(\bigcup_{i-1}^{m}\bar{A_i}\) ,时间复杂度为:\(O(2^mm)\)

  • 那么现在我们要做的就是求出\(\bar{A_i}\),那么我们分析一下:

对于不满足\(u\)和\(v\)的限制条件的方案数\(\bar{A_i}\),只要\(u\)和\(v\)之间的所有边都涂成白色,那么其他不在\(u\)和\(v\)之间的边,颜色就可以随便涂,设\(u\)和\(v\)之间的边数为\(cnt\),那么

\[\bar{A_i} = 2^{n-1-cnt}
\]
  • 我们已经知道了\(\bar{A_i}\)怎么求,只要知道\(u\)和\(v\)之间的边数即可,但是我们在进行容斥的时候我们需要求出多个不合法方案之间的交集,那么交集就意味着我们涂的方案需要使得多个限制条件同时无法满足,即我们需要将所有限制条件里的边都涂成白色,所以说我们需要知道多个限制条件中边的并集,也就是说我们需要知道每个限制条件\(u\)和\(v\)之间的边具体有哪些边,我们考虑如何解决这个问题:

    因为\(n \le 50\),所以我们不妨将每个点到根节点的路径中边的状态利用二进制压缩,我们设点\(u\)到根节点的路径中边的状态为\(path_u\),我们设第\(i\)个限制条件\((u,v)\)之间边的信息为\(info_i\),利用树上异或的性质:
\[info_{i} = path_u \bigoplus path_v
\]

我们可以求出\(u\)和\(v\)之间有哪些边存在

  • 对于多个限制条件中边的并集的状态\(num\)为
\[\sum num\ \ |= \ \ info_i
\]
  • 设状态\(num\)中\(1\)的数量为\(cnt\)(即边的数量),那么对于不满足多个限制条件的方案的交集为
\[2^{n-1-cnt}
\]
  • 最后利用容斥原理解题即可
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 50 + 10, M = 4e5 + 10; int n, m;
vector<int> g[N];
int path[N];
int info[N]; void dfs(int u, int par)
{
path[u] = path[par] | (1ll << u);
for (auto v : g[u])
{
if (v == par)
continue;
dfs(v, u);
}
} void solve()
{
cin >> n;
for (int i = 1, u, v; i < n; ++i)
{
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
cin >> m;
for (int i = 0, u, v; i < m; ++i)
{
cin >> u >> v;
info[i] = path[u] ^ path[v];
}
int ans = 0;
for (int i = 1; i < (1 << m); ++i)
{
int cnt = 0;
int num = 0;
for (int j = 0; j < m; ++j)
{
if (i >> j & 1)
{
cnt++;
num |= info[j];
}
}
int free = n - 1 - __builtin_popcountll(num);
if (cnt % 2 == 1)
ans += (1ll << free);
else
ans -= (1ll << free);
}
cout << (1ll << (n - 1)) - ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

AtCoder Beginner Contest 152的更多相关文章

  1. AtCoder Beginner Contest 100 2018/06/16

    A - Happy Birthday! Time limit : 2sec / Memory limit : 1000MB Score: 100 points Problem Statement E8 ...

  2. AtCoder Beginner Contest 052

    没看到Beginner,然后就做啊做,发现A,B太简单了...然后想想做完算了..没想到C卡了一下,然后还是做出来了.D的话瞎想了一下,然后感觉也没问题.假装all kill.2333 AtCoder ...

  3. AtCoder Beginner Contest 053 ABCD题

    A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...

  4. AtCoder Beginner Contest 136

    AtCoder Beginner Contest 136 题目链接 A - +-x 直接取\(max\)即可. Code #include <bits/stdc++.h> using na ...

  5. AtCoder Beginner Contest 137 F

    AtCoder Beginner Contest 137 F 数论鬼题(虽然不算特别数论) 希望你在浏览这篇题解前已经知道了费马小定理 利用用费马小定理构造函数\(g(x)=(x-i)^{P-1}\) ...

  6. AtCoder Beginner Contest 076

    A - Rating Goal Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Takaha ...

  7. AtCoder Beginner Contest 079 D - Wall【Warshall Floyd algorithm】

    AtCoder Beginner Contest 079 D - Wall Warshall Floyd 最短路....先枚举 k #include<iostream> #include& ...

  8. AtCoder Beginner Contest 064 D - Insertion

    AtCoder Beginner Contest 064 D - Insertion Problem Statement You are given a string S of length N co ...

  9. AtCoder Beginner Contest 075 D - Axis-Parallel Rectangle【暴力】

    AtCoder Beginner Contest 075 D - Axis-Parallel Rectangle 我要崩溃,当时还以为是需要什么离散化的,原来是暴力,特么五层循环....我自己写怎么都 ...

  10. AtCoder Beginner Contest 075 C bridge【图论求桥】

    AtCoder Beginner Contest 075 C bridge 桥就是指图中这样的边,删除它以后整个图不连通.本题就是求桥个数的裸题. dfn[u]指在dfs中搜索到u节点的次序值,low ...

随机推荐

  1. Python存储与读写二进制文件

    技术背景 一般情况下我们会选择使用明文形式来存储数据,如json.txt.csv等等.如果是需要压缩率较高的存储格式,还可以选择使用hdf5或者npz等格式.还有一种比较紧凑的数据存储格式,就是直接按 ...

  2. SQL查折线图数据

    在做后台管理系统的时候,有很大概率是要与各种图表数据打交道, 那么如何通过SQL查出基本图表的数据呢,以折线图为例, X轴为日期,Y轴为统计数据,那么我们通过SQL如何查询出连续日期下的统计数据呢, ...

  3. parser.add_argument

    parser.add_argument 在解析参数时,有个地方很值得注意. --dict-name,会把dict-name解析为变量dict_name.也就是说会把破折号转成下划线.

  4. WPF 实现一个吃豆豆的Loading加载动画

    运行的效果如下 先引入一下我们需要的库 在nuget上面搜一下"expression.Drawing",安装一下这个包 我们再创建一个Window,引入一下这个包的命名空间 我们设 ...

  5. String 的 intern() 方法

    问题: String s1 = "a" + "b"; //创建了几个对象? String s2 = new String("ab"); // ...

  6. JAVAEE——tomcat安装

    一.下载 1.网址:Tomcat官网 选择版本:点击左边Download下的which version,根据Supported Java Versions来选择合适的Tomcat版本 下载软件:点击左 ...

  7. Flutter Web 近期的重要更新

    我们的发布重点优先关注在性能.开发者体验以及 Web 集成上 2021 年 3 月 Flutter Web 支持已进入稳定版,那么,下一步是什么? 我们对用户研究发现,有超过 10% 的 Flutte ...

  8. 即刻报名 | Flutter Engage China 线上见!

    在刚刚过去的 Flutter Engage 活动上,我们正式发布了 Flutter 2: 为任何平台创建美观.快速且可移植应用的能力得以更上一层楼.通过 Flutter 2,开发者可以使用相同的代码库 ...

  9. 【赵渝强老师】使用MongoDB的命令行工具:mongoshell

    一.启动mongo shell 安装好MongoDB后,直接在命令行终端执行下面的命令: mongo 如下图所示: 可选参数如下: 也可以简写为: 在mongo shell中使用外部编辑器,如:vi, ...

  10. OpenGL和OpenCL区别

    1.OpenGL用于图形渲染程序:OpenCL用于复杂的计算.他们都是由Khronos管理并使用C语言编译. 2.OpneGL使编程能够进行图形操作:OpenCL使编程能够在多个处理器中进行计算. 3 ...