A
a题的思路就是直接暴力模拟出所有的可能性,这里可以用到在bfs求最短通路中的一种枚举形式.
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int a, b, x1, y1, x2, y2;
cin >> a >> b >> x1 >> y1 >> x2 >> y2;
int dx[8] = { a,-a,a,-a,b,-b,b,-b };
int dy[8] = { b,-b,-b,b,a,-a,-a,a };//列举出一个点的八种可能性,就是这匹马的八个位置
int ans = 0;
for (int i = 0; i < (a == b ? 4 : 8); i++)//判断a,b是否相等,如果相等就只会有四种走法
{
int nx = x1 + dx[i];
int ny = y1 + dy[i];
if ((abs(x2 - nx) == a && abs(y2 - ny) == b) || (abs(x2 - nx) == b && abs(y2 - ny) == a))ans++;
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while (_--)solve();
}
本题我学会了什么:在类似有关到坐标系枚举的问题时,可以考虑用数组来模拟他的所有走法,然后进行判断.
B
题意:b题的题意也很好理解,就是选定一个数,然后其他数为一个数组,如果这个数大于其中某个数,就删去那个数,然后加到这个数上,最后要判断每个位置的数最多能删去多少个数.
分析:这个题目我们肯定是要排序的,但是最终结果输出又和下标有关系,毫无疑问,我们是要记录下标的,这个时候我们要考虑开一个结构体,同时规定一个cmp函数来说明排序顺序,在排序完后,我们就可以进行类似于双指针的操作
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
struct point
{
int idx;
ll num;
}a[N];
int b[N];
bool cmp(point a, point b)
{
return a.num < b.num;
}//cmp规定以num为判断的标准
void solve()
{
int n; cin >> n;
for (int i = 0; i <= n - 1; ++i)
{
cin >> a[i].num;
a[i].idx = i;
}
sort(a, a + n, cmp);
ll sum = 0;
int j = 0;
for (int i = 0; i <= n - 1; ++i)
{
while (j <= i)
{
sum += a[i].num;
j++;
}//因为a数组已经排序过,所以在i前面的数肯定小于a[i]无脑加上就行,最后答案也肯定会大于i-1
while (j < n && sum >= a[j].num)
{
sum += a[j].num;
j++;
}//到这里就是判断a[i]后面那些比他本身要大的数了,这个时候就要考虑前面的和是否大于后面的数了
b[a[i].idx] = j - 1;//b数组就是最后的答案,记得要按a[i]的下标来
}
for (int i = 0; i <= n - 1; ++i)cout << b[i] << ' ';
cout << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while (_--)solve();
}
关键:对比ai大和比ai小的那些数分开进行讨论
C
我们可以知道,当k>=3时,就一定可以对同一对数进行两次操作,然后再把新产生的两个数进行操作来得到0,那么我们就只要讨论k==1和k==2的情况,k==1的情况其实很好讨论,就是开个ai-ai-1的数组,然后输出最小值就行了,而k==2需要我们进行遍历,并且在每一次遍历中去原数组中找到和新产生的数最相近的两个数,然后把他们的差值与原数组最小值以及他自身进行比较
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
{
int n, k; cin >> n >> k;
vector<ll>a(n);
for (int i = 0; i <= n - 1; ++i)cin >> a[i];
sort(a.begin(), a.end());
if (k >= 3)
{
cout << 0 << '\n';
return;
}//若大于等于3,直接输出0即可
else
{
ll mi = a[0];
for (int i = 0; i <= n - 2; ++i)
{
mi = min((a[i + 1] - a[i]), mi);
}//求出原数组中差值的最小值
if (k == 1)
{
cout << mi << '\n';
}
else
{
for(int i=0;i<=n-1;++i)
for (int j = 0; j <= n - 1; ++j)
{
if (i == j)continue;
int idx = lower_bound(a.begin(), a.end(), abs(a[i] - a[j])) - a.begin();//lower_bound减去begin()函数来记录下标
if (idx != n)mi = min(abs(a[idx] - abs(a[i] - a[j])), mi);
if (idx != 0)mi = min(abs(abs(a[i] - a[j]) - a[idx - 1]), mi);//前面两个限制条件都是为了防止数组越界
mi = min(abs(a[i] - a[j]), mi);
}
cout << mi << '\n';
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
while (_--)solve();
}
关键:本题难点在于分析k==2的情况,这时要注意他进行第二次操作时是对与ai相差最小的两个数进行计算,此时可以考虑用二分查找的lower_bound来返回下标,这题的最后就是对 ai-aj 与 ai-aj-a[idx]以及ai-aj-a[idx-1]三个数进行比较。