C. Candy Store

C. Candy Store

The store sells n types of candies with numbers from 1 to n. One candy of type i costs bi coins. In total, there are ai candies of type i in the store.

You need to pack all available candies in packs, each pack should contain only one type of candies. Formally, for each type of candy i you need to choose the integer di, denoting the number of type i candies in one pack, so that ai is divided without remainder by di.

Then the cost of one pack of candies of type i will be equal to bidi. Let's denote this cost by ci, that is, ci=bidi.

After packaging, packs will be placed on the shelf. Consider the cost of the packs placed on the shelf, in order c1,c2,,cn. Price tags will be used to describe costs of the packs. One price tag can describe the cost of all packs from l to r inclusive if cl=cl+1==cr. Each of the packs from 1 to n must be described by at least one price tag. For example, if c1,,cn=[4,4,2,4,4], to describe all the packs, a 3 price tags will be enough, the first price tag describes the packs 1,2, the second: 3, the third: 4,5.

You are given the integers a1,b1,a2,b2,,an,bn. Your task is to choose integers di so that ai is divisible by di for all i, and the required number of price tags to describe the values of c1,c2,,cn is the minimum possible.

For a better understanding of the statement, look at the illustration of the first test case of the first test:

Let's repeat the meaning of the notation used in the problem:

ai — the number of candies of type i available in the store.

bi — the cost of one candy of type i.

di — the number of candies of type i in one pack.

ci — the cost of one pack of candies of type i is expressed by the formula ci=bidi.

Input

Each test contains multiple test cases. The first line contains the number of test cases t (1t100000). Description of the test cases follows.

The first line of each test case contains a single integer n (2n200000) — the number of types of candies.

Each of the next n lines of each test case contains two integers ai and bi (1ai109, 1bi10000) — the number of candies and the cost of one candy of type i, respectively.

It is guaranteed that the sum of n over all test cases does not exceed 200000.

Output

For each test case, output the minimum number of price tags required to describe the costs of all packs of candies in the store.

Example

input

复制代码
5
4
20 3
6 2
14 5
20 7
3
444 5
2002 10
2020 2
5
7 7
6 5
15 2
10 3
7 7
5
10 1
11 5
5 1
2 2
8 2
6
7 12
12 3
5 3
9 12
9 3
1000000000 10000
复制代码

output

2
1
3
2
5

Note

In the first test case, you can choose d1=4, d2=6, d3=7, d4=5. Then the cost of packs will be equal to [12,12,35,35]. 2 price tags are enough to describe them, the first price tag for c1,c2 and the second price tag for c3,c4. It can be shown that with any correct choice of di, at least 2 of the price tag will be needed to describe all the packs. Also note that this example is illustrated by a picture in the statement.

In the second test case, with d1=4, d2=2, d3=10, the costs of all packs will be equal to 20. Thus, 1 price tag is enough to describe all the packs. Note that ai is divisible by di for all i, which is necessary condition.

In the third test case, it is not difficult to understand that one price tag can be used to describe 2nd, 3rd and 4th packs. And additionally a price tag for pack 1 and pack 5. Total: 3 price tags.

 

解题思路

  先给出比赛时想到的做法。思路比较暴力,代码也很长。

  对于总数量为ai的糖果,第i种糖果的每一小包中允许的数量为ai的约数。因此容易想到直接分解得到每个ai的所有约数,然后每个约数都乘上bi,那么就得到第i种糖果允许存在的所有代价。最后从前往后枚举所有糖果并尽可能取合法代价的交集,这部分当时比赛没想到,后面再细说。

  首先每个ai最大能够取到109,如果直接暴力分解约数那么时间复杂度就是O(109n),肯定会TLE。这个时候我们就退而求次,先筛出109内的所有素数,然后对ai分解质因数,由于在109内一个数最多有1344个约数,因此可以直接通过质因数来暴搜找到ai的所有约数,那么时间复杂度就降到了O(n(109ln109+1344))级别,其中109内的素数个数为3400个左右,因此计算量大约是108级别,时间限制为3s感觉不会T(?)。

  其实按照我现在这种做法在cf上面不会T(2023-03-27),但为了保证严谨性,我特意构造了组极限数据跑了下,然后我成功把自己给hack了。构造的数据很简单,就是a=735134400, b=1a=3, b=1共交替出现2×105次就可以了。其中7351344001344个约数,且3735134400

  但还是继续说一下做法吧。现在给出了种还可以的分解质因数的方法,接下来就是如何选代价的问题了。假设第i种糖果的代价为集合ci,如果第i+1种糖果想与第i种糖果的代价一样,那么很明显能选的代价为两个集合cici+1的交集。以此类推,如果第l种糖果到第r种糖果的代价都相同,那么就要满足i=lrci

  因此我们可以从前往后枚举i,对于第i种糖果每次求cici1的交集(此时的ci1clci1的交集),如果得到的结果不为空,那么说明第li种糖果可以有相同的代价。如果直接暴力求两个集合的交集那么时间复杂度是O(|ci||ci1|),一共要求n个集合的交集,必定会超时。因此在求交集的部分需要优化。

  注意到对于xcici1必定满足xbixbiai,因此我们只需要枚举ci1的每一个元素x,如果x满足这两个条件那么我们就保留x,时间复杂度就降到了O(n|ci1|)O(1344n)。可以发现甚至第i种糖果的代价都不需要求了(即不需要对ai分解约数)。而如果在这个过程中没有选到任何元素,即交集为空,我们才需要求第i种糖果的代价ci

  TLE代码如下:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 2e5 + 10;
 7 
 8 int primes[N], cnt;
 9 bool vis[N];
10 int a[N], b[N];
11 vector<vector<int>> fs;
12 vector<LL> c[N];
13 
14 void get_prime(int n) {
15     for (int i = 2; i <= n; i++) {
16         if (!vis[i]) primes[cnt++] = i;
17         for (int j = 0; primes[j] <= n / i; j++) {
18             vis[primes[j] * i] = true;
19             if (i % primes[j] == 0) break;
20         }
21     }
22 }
23 
24 void dfs(int k, int u, int prod) {
25     if (u == fs.size()) {    // 找到约数prod
26         c[k].push_back(1ll * prod * b[k]);    // 记录第k种糖果所有可能的代价
27         return;
28     }
29     int t = 1, p = fs[u][0], s = fs[u][1];
30     for (int i = 0; i <= s; i++) {
31         dfs(k, u + 1, prod * t);
32         t *= p;
33     }
34 }
35 
36 void get(int k) {
37     fs.clear();
38     int t = a[k];
39     for (int i = 0; primes[i] <= t / primes[i]; i++) {    // 质因数分解
40         int p = primes[i];
41         if (t % p == 0) {
42             int s = 0;
43             while (t % p == 0) {
44                 t /= p;
45                 s++;
46             }
47             fs.push_back({p, s});
48         }
49     }
50     if (t > 1) fs.push_back({t, 1});
51     dfs(k, 0, 1);    // 暴搜出a[k]的所有约数
52 }
53 
54 void solve() {
55     int n;
56     scanf("%d", &n);
57     for (int i = 0; i < n; i++) {
58         scanf("%d %d", a + i, b + i);
59         c[i].clear();
60     }
61     get(0);    // 求第0种糖果的所有可能代价
62     int ret = 1;    // 答案至少是1
63     for (int i = 1; i < n; i++) {
64         for (auto &x : c[i - 1]) {    // 求交集
65             if (x % b[i] == 0 && a[i] % (x / b[i]) == 0) c[i].push_back(x);
66         }
67         if (c[i].empty()) {    // 交集为空
68             ret++;    // 需要的代价种类+1
69             get(i);    // 求第i种糖果的所有可能代价
70         }
71     }
72     printf("%d\n", ret);
73 }
74 
75 int main() {
76     get_prime(N - 1);    // 筛出sqrt(1e9)内的质数,用于质因数分解
77     int t;
78     scanf("%d", &t);
79     while (t--) {
80         solve();
81     }
82     
83     return 0;
84 }
复制代码

  下面给出正解,是真想不到。

  假设第l种糖果到第r种糖果的代价一样,令ci=dibi,即有cl=cl+1==cr=x,其中diai

  那么可以发现对于i[l,r]bix的一个因子,即xbi的倍数,因此必然有lcm[bl,,br]x

  同时由于diai,因此有dibiaibi,即xaibi的一个因子,这就等价于xgcd(cl,,cr)

  因此如果有cl=cl+1==cr,那么必然有lcm[bl,,br]gcd(albl,,arbr),反过来也成立。

  然后从前往后枚举,维护连续序列的最大公约数d和最小公倍数m,贪心地选择,即如果满足md则使用同一个代价,而如果md则说明需要开另外一个代价。

  AC代码如下,时间复杂度为O(nlog109)

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 LL gcd(LL a, LL b) {
 7     return b ? gcd(b, a % b) : a;
 8 }
 9 
10 LL lcm(LL a, LL b) {
11     return a / gcd(a, b) * b;
12 }
13 
14 void solve() {
15     int n;
16     scanf("%d", &n);
17     LL d = 0, m = 1;
18     int ret = 1;
19     while (n--) {
20         LL a, b;
21         scanf("%lld %lld", &a, &b);
22         m = lcm(m, b);
23         d = gcd(d, a * b);
24         if (d % m) {
25             ret++;
26             d = a * b, m = b;
27         }
28     }
29     printf("%d\n", ret);
30 }
31 
32 int main() {
33     int t;
34     scanf("%d", &t);
35     while (t--) {
36         solve();
37     }
38     
39     return 0;
40 }
复制代码

 

参考资料

  Codeforces Round 860 (Div. 2) A~E:https://zhuanlan.zhihu.com/p/617245703

  Editorial of Codeforces Round 860 (Div. 2):https://codeforces.com/blog/entry/114208

posted @   onlyblues  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-03-27 图中的环
2022-03-27 合适数对
Web Analytics
点击右上角即可分享
微信分享提示