Codeforces Round 993 (Div. 4)个人训练记录
Codeforces Round 993 (Div. 4)
只选择对我有价值的题目记录
E. Insane Problem
题目描述
给定五个整数 k k k, l 1 l_1 l1, r 1 r_1 r1, l 2 l_2 l2 和 r 2 r_2 r2,Wave 希望你帮助她计算满足以下所有条件的有序对 ( x , y ) (x, y) (x,y) 的数量:
- l 1 ≤ x ≤ r 1 l_1 \leq x \leq r_1 l1≤x≤r1。
- l 2 ≤ y ≤ r 2 l_2 \leq y \leq r_2 l2≤y≤r2。
- 存在一个非负整数 n n n,使得 y x = k n \frac{y}{x} = k^n xy=kn。
输入
- 第一行包含一个整数 t t t( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1≤t≤104),这里的 t t t 表示测试用例的数量。
- 对于每个测试用例,其唯一的一行包含五个整数 k k k, l 1 l_1 l1, r 1 r_1 r1, l 2 l_2 l2 和 r 2 r_2 r2( 2 ≤ k ≤ 1 0 9 2 \leq k \leq 10^9 2≤k≤109, 1 ≤ l 1 ≤ r 1 ≤ 1 0 9 1 \leq l_1 \leq r_1 \leq 10^9 1≤l1≤r1≤109, 1 ≤ l 2 ≤ r 2 ≤ 1 0 9 1 \leq l_2 \leq r_2 \leq 10^9 1≤l2≤r2≤109)。
输出
对于每个测试用例,在新的一行输出匹配的有序对 ( x , y ) (x, y) (x,y) 的数量。
示例
Input(输入) | Output(输出) |
---|---|
5 2 2 6 2 12 2 1 1000000000 1 1000000000 3 5 7 15 63 1000000000 1 5 6 1000000000 15 17 78 2596 20914861 | 12 1999999987 6 1 197 |
注意事项
- 在第三个测试用例中,匹配的有序对如下:
- ( 5 , 15 ) (5, 15) (5,15)
- ( 5 , 45 ) (5, 45) (5,45)
- ( 6 , 18 ) (6, 18) (6,18)
- ( 6 , 54 ) (6, 54) (6,54)
- ( 7 , 21 ) (7, 21) (7,21)
- ( 7 , 63 ) (7, 63) (7,63)
- 在第四个测试用例中,唯一有效的有序对是 ( 1 , 1000000000 ) (1, 1000000000) (1,1000000000)。
思路:
枚举加计数问题,通常只需要枚举其中一个,然后另一个是可以通过计算得到的。由于
x
和y
的范围告诉我们了,所以 k n k^n kn的范围我们也能知晓,上界为 r = r 2 / l 1 r=r_2 / l_1 r=r2/l1下取整,下界为 l = ( l 2 + r 1 − 1 ) / r 1 l = (l_2 + r_1 - 1) / r_1 l=(l2+r1−1)/r1向上取整。现在我们只需要调整一下方程为 y k n = x \frac{y}{k^n} = x kny=x,每枚举一个可行的 k n k^n kn后,我们用y的最小值和最大值即可求出在这个可行的 k n k^n kn下x
的范围,通过计算即可得到个数。至于为啥要将方程调整成除法形式而不是更好计算的形式,自己思考一下就能明白,用乘法的话得到的y
值不是一个接一个的,中间有很多空隙,导致不能直接通过计算得到个数,用除法可以解决这样的问题。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'using namespace std;void solve(){int k,l1,r1,l2,r2;cin>>k>>l1>>r1>>l2>>r2;int l = (l2+r1-1)/r1;//下界int r = r2/l1; //上界int base = 1;int ans = 0;// cout<<l<<" "<<r<<endl;while(base<l) base*=k; //先找到范围内最小的k^nwhile(base<=r){int ll = (l2+base-1) / base;int rr = r2 / base;ll = max(l1,ll);rr = min(r1,rr);if(ll<=rr) ans += rr-ll+1;base*=k;}cout<<ans<<endl;
}signed main(){int T; cin>>T; while(T--)solve();return 0;
}
评述
这道题比较有参考价值,自己太笨了,第一时间竟然无从下手
----------------------------------------
F. Easy Demon Problem
题目描述
对于任意网格,Robot 将其美感定义为网格中元素的总和。
Robot 给出了一个长度为 n n n 的数组 a a a 和一个长度为 m m m 的数组 b b b 。你构造了一个 n n n 乘 m m m 的网格 M M M ,使得所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n 和 1 ≤ j ≤ m 1 \leq j \leq m 1≤j≤m 都是 M i , j = a i ⋅ b j M_{i,j}=a_i\cdot b_j Mi,j=ai⋅bj 。
然后,Robot 会给出 q q q 个查询,每个查询都包含一个整数 x x x 。对于每个查询,请判断是否可以***精确地执行一次下面的操作,从而使 M M M 具有 x x x 的美感:
- 选择整数 r r r 和 c c c ,使得 1 ≤ r ≤ n 1 \leq r \leq n 1≤r≤n 和 1 ≤ c ≤ m 1 \leq c \leq m 1≤c≤m 都是整数。
- 设 M i , j M_{i,j} Mi,j 为 0 0 0 ,所有有序对 ( i , j ) (i,j) (i,j) 都是 i = r i=r i=r , j = c j=c j=c ,或都是 i = r i=r i=r 。
请注意,查询是不持久的,也就是说,在查询过程中,您不会将任何元素设置为 0 0 0 --您只需要输出是否可以找到 r r r 和 c c c ,如果执行了上述操作,网格的美观度将为 x x x 。此外,请注意,即使原始网格的美观度已经是 x x x ,您也必须对每个查询执行上述操作。
输入
第一行包含三个整数 n n n 、 m m m 和 q q q ( 1 ≤ n , m ≤ 2 ⋅ 1 0 5 , 1 ≤ q ≤ 5 ⋅ 1 0 4 1 \leq n,m \leq 2\cdot 10^5, 1 \leq q \leq 5\cdot 10^4 1≤n,m≤2⋅105,1≤q≤5⋅104 )–分别是 a a a 的长度、 b b b 的长度和查询次数。
第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an ( 0 ≤ ∣ a i ∣ ≤ n 0 \leq |a_i| \leq n 0≤∣ai∣≤n )。
第三行包含 m m m 个整数 b 1 , b 2 , … , b m b_1, b_2, \ldots, b_m b1,b2,…,bm ( 0 ≤ ∣ b i ∣ ≤ m 0 \leq |b_i| \leq m 0≤∣bi∣≤m )。
下面的 q q q 行中各包含一个整数 x x x ( 1 ≤ ∣ x ∣ ≤ 2 ⋅ 1 0 5 1 \leq |x| \leq 2\cdot 10^5 1≤∣x∣≤2⋅105 ),即通过将一行和一列中的所有元素都设置为 0 0 0 所获得的网格美感。
输出
对于每个测试用例,如果有办法执行上述操作,从而使美景为 x x x ,则输出 “YES”(不带引号),否则输出 “NO”(不带引号)。
您可以在任何情况下输出 "YES "和 “NO”(例如,字符串 “yES”、"yes "和 "Yes "将被视为肯定回答)。
样例1
3 3 6
-2 3 -3
-2 2 -1
-1
1
-2
2
-3
3
输出
NO
YES
NO
NO
YES
NO
思路
评述
一道不错的题就是题目有点难读,其中提前预处理出所有情况再来处理询问的方式可以很有效的降低时间复杂度,也是这种题的经典做法。
#include <bits/stdc++.h>using namespace std;using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLLconst int N = 2e5 + 5;bool visA[2 * N + 5];
bool visB[2 * N + 5];bool ans[2 * N + 5];
void solve()
{int n, m, q;cin >> n >> m >> q;std::vector<ll> a(n);ll sumA = 0;for (int i = 0; i < n; i++){cin >> a[i];sumA += a[i];}std::vector<ll> b(m);ll sumB = 0;for (int i = 0; i < m; i++){cin >> b[i];sumB += b[i];}for (int i = 0; i < n; i++){ll d = sumA - a[i];if (abs(d) < N)visA[d + N] = 1;}for (int i = 0; i < m; i++){ll d = sumB - b[i];if (abs(d) < N)visB[d + N] = 1;}for (int i = 1; i < N; i++){for (int j = 1; j * i < N; j++){ans[N + i * j] |= visA[N + i] && visB[N + j];ans[N + i * j] |= visA[N - i] && visB[N - j];ans[N - i * j] |= visA[N + i] && visB[N - j];ans[N - i * j] |= visA[N - i] && visB[N + j];}}while (q--){int x;cin >> x;x += N;if (ans[x])cout << "YES\n";elsecout << "NO\n";}
}int main()
{ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);// freopen("test.in", "r", stdin);// freopen("test.out", "w", stdout);int _ = 1;// std::cin >> _;while (_--){solve();}return 0;
}