F.Interview
题意:我们有n堆石头,没一堆的重量都是1,但是经过一些事情后,有一堆的重量发生了变化,变成了2,问我们能在30次中找到这一堆中的重量改变的那一组(注意本题是一个交互题目)
思路:
本题看到30次提问机会和范围只有2e5,很容易想到二分去做,我们先将这些石头当作正常的重量来求一个前缀和,根据我们询问的那一部分区间的重量我们来判断重量增加的那一组在什么位置,不断二分,次数肯定时小于20次的。写的时候一定要注意格式(不要加上解绑啥的,容易wrong)
具体代码如下:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ULL;
const int N = 1500, M = 1000000 + 10;
int ask(int l, int r)
{
cout << "? " << r - l + 1 << " ";
for (int i = l; i <= r; i++)
{
cout << i << " ";
}
cout << endl;
int ans;
cin >> ans;
return ans;
}
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1), q(n + 1, 0);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
q[i] = q[i - 1] + a[i];
}
int l = 1, r = n;
while (l < r)
{
int mid = l + r >> 1;
int s = q[mid] - q[l - 1];
int w = ask(l, mid);
if (s < w)
r = mid;
else
l = mid + 1;
}
cout << "! " << l << endl;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
F.Bouncy Ball
题意:给我们一个网格,上面有一个小球,问我们在经过一系列的反弹后是否能够经过一个目标点。
思路:n*m不会超过5e4范围比较小,我们可以直接一步一步的枚举,直接算出答案是多少。
代码实现;
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ULL;
const int N = 1500, M = 1000000 + 10;
void solve()
{
int n, m, x1, y1, x2, y2, X, Y, ans = 0;
cin >> n >> m >> x1 >> y1 >> x2 >> y2;
string str;
cin >> str;
if (str[0] == 'D')
X = 1;
else
X = -1;
if (str[1] == 'R')
Y = 1;
else
Y = -1;
int T = n * m * 4, x = x1, y = y1;
while (T--)
{
if (x == x2 && y == y2)
{
cout << ans << endl;
return;
}
bool f = 0;
if (X == 1 && x == n)
{
X = -1;
f = 1;
}
if (X == -1 && x == 1)
{
X = 1;
f = 1;
}
if (Y == 1 && y == m)
{
Y = -1;
f = 1;
}
if (Y == -1 && y == 1)
{
Y = 1;
f = 1;
}
if (f)
ans++;
x += X, y += Y;
}
cout << -1 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
G1,G2G2. Subsequence Addition
题意:有 T 组询问,每组询问给定一个长度为 n 的序列 s。如果存在一个初始长度为 1,且只包含数字 1 的序列 a,经过若干次操作后长度变为 n,每次操作选取当前序列的某个子序列,将这个子序列的每一位的值加起来,并将最后的值加入序列,使序列的长度加 1。询问是在序列长度变为 n 时,序列 a 是否与序列 s 相同?
思路:
首先,让我们来考虑一个最简单的情况。如果某个整数 a 的二进制表示与另一个整数 s 的二进制表示相等,那么 s 的某一位必定为 1,因为 a 的初始值为 1。同时,每次操作都是将一个数加入序列中,而并没有要求必须将数加在序列的末尾。因此,a 序列中数的顺序可以改变。为了方便处理,我们可以对序列 s 进行排序,这与对序列 a 进行排序是等价的。而且由于我们并不清楚序列 a 具体是什么样子,所以这样的处理更具有普遍性。
接下来,我们要注意每次操作都是将序列的子序列中的值加入到整个序列中。因此,将序列 s 进行排序(从小到大),然后考虑第 i 个位置的值,它是不可能大于前面 1 到 i-1 位置的值之和的。这一点可以保证当不满足判断条件时,题目中给定的变换是不可能实现的。
最后,除了以上两种情况,我们肯定能够通过一系列操作将序列 a 转变为序列 s。因此,最终的输出是YES。总的时间复杂度为 O(Tnlogn),其中 T 是测试用例的数量,n 是序列的长度。通过这样的方法,可以解决这两道题目。
实现代码:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ULL;
const int N = 1500, M = 1000000 + 10;
// ll a[N], q[N];
void solve()
{
int n;
cin >> n;
vector<ll> a(n + 1), q(n + 10);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a.begin() + 1, a.end());
// sort(a + 1, a + 1 + n);
q[2] = 1;
for (int i = 3; i <= n; i++)
q[i] = q[i - 1] + a[i - 1];
if (a[1] > 1)
{
cout << "NO" << endl;
return;
}
for (int i = 2; i <= n; i++)
{
if (a[i] > q[i])
{
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}