Codeforces Round 993 (Div. 4)(补题)

Codeforces Round 993 (Div. 4)

只选择对我有价值的题目记录

E. Insane Problem

题目描述

给定五个整数 kl1r1l2r2,Wave 希望你帮助她计算满足以下所有条件的有序对 (x,y) 的数量:

  1. l1xr1
  2. l2yr2
  3. 存在一个非负整数 n,使得 yx=kn

输入

  1. 第一行包含一个整数 t1t104),这里的 t 表示测试用例的数量。
  2. 对于每个测试用例,其唯一的一行包含五个整数 kl1r1l2r22k1091l1r11091l2r2109)。

输出

对于每个测试用例,在新的一行输出匹配的有序对 (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,45)
    • (6,18)
    • (6,54)
    • (7,21)
    • (7,63)
  • 在第四个测试用例中,唯一有效的有序对是 (1,1000000000)

思路:

枚举加计数问题,通常只需要枚举其中一个,然后另一个是可以通过计算得到的。由于xy的范围告诉我们了,所以kn的范围我们也能知晓,上界为r=r2/l1下取整,下界为l=(l2+r11)/r1向上取整。现在我们只需要调整一下方程为ykn=x,每枚举一个可行的kn后,我们用y的最小值和最大值即可求出在这个可行的knx的范围,通过计算即可得到个数。至于为啥要将方程调整成除法形式而不是更好计算的形式,自己思考一下就能明白,用乘法的话得到的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^n
while(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 的数组 a 和一个长度为 m 的数组 b 。你构造了一个 nm 的网格 M ,使得所有 1in1jm 都是 Mi,j=aibj

然后,Robot 会给出 q 个查询,每个查询都包含一个整数 x 。对于每个查询,请判断是否可以***精确地执行一次下面的操作,从而使 M 具有 x 的美感:

  1. 选择整数 rc ,使得 1rn1cm 都是整数。
  2. Mi,j0 ,所有有序对 (i,j) 都是 i=rj=c ,或都是 i=r

请注意,查询是不持久的,也就是说,在查询过程中,您不会将任何元素设置为 0 --您只需要输出是否可以找到 rc ,如果执行了上述操作,网格的美观度将为 x 。此外,请注意,即使原始网格的美观度已经是 x ,您也必须对每个查询执行上述操作。

输入

第一行包含三个整数 nmq ( 1n,m2105,1q5104 )--分别是 a 的长度、 b 的长度和查询次数。

第二行包含 n 个整数 a1,a2,,an ( 0|ai|n )。

第三行包含 m 个整数 b1,b2,,bm ( 0|bi|m )。

下面的 q 行中各包含一个整数 x ( 1|x|2105 ),即通过将一行和一列中的所有元素都设置为 0 所获得的网格美感。

输出

对于每个测试用例,如果有办法执行上述操作,从而使美景为 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 0x3f3f3f3f3f3f3f3fLL
const 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";
else
cout << "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;
}

本文作者:califeee

本文链接:https://www.cnblogs.com/califeee/p/18624120

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   califeee  阅读(34)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.