A
给定(n)个数分别为(a_1,a_2,...,a_n),构造出一组(b_1,b_2,...,b_n)使得(a_1 imes b_1 + a_2 imes b_2 + ... + a_n imes b_n = 0) ((a_i)和(b_i)必须是非(0)的数且不超过(100)) 且(n)为偶数。
从(n)为偶数作为切入点,直接输出(a_{i+1}) 和 (-a_i),使得(a_i imes a_{i + 1} + a_{i + 1} imes -a_i = 0)。同理,输出(-a_{i + 1})和(a_i)也可。
#include <bits/stdc++.h>
using namespace std;
const int N = 100 + 20;
int n;
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for(int i = 1; i <= n; i += 2)
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d %d ", -y, x);
}
puts("");
}
//system("pause");
return 0;
}
B
对于一个(n imes m)的矩阵,给出它每行的顺序和它每列的顺序,还原这个矩阵。
因为矩阵里的数一定是不重复的从(1)到(n imes m)的数,对于每个二维坐标,记录每个数的行和列,然后反过来用二维数组的行列对应这个值,输出即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 20;
int r[N * N], c[N * N], a[N][N];
int n, m, x;
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= m; ++ j)
scanf("%d", &x), c[x] = j;
for(int i = 1; i <= m; ++ i)
for(int j = 1; j <= n; ++ j)
scanf("%d", &x), r[x] = j;
for(int i = 1; i <= n * m; ++ i) a[r[i]][c[i]] = i;
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= m; ++ j)
printf("%d%c", a[i][j], j == m ? '
' : ' ');
}
//system("pause");
return 0;
}
C
给定(n)个数,和(6)个基准数,对于(n)个数中的每一个,必须选择(6)个数中的一个作差,使得到的(n)个差值中最大差值和最小差值的差最小。
将(n)个数中每一个和(6)个基准数都做一下差,并标记一下这是第(i)个数与基准数得到的差,将这个差从小到大排序,然后双指针扫序列,当双指针区域里包含(n)个数得到的差(()每个数至少(1)个())时,并且这个区域不能再缩小时,统计答案,扫完一遍序列即可得到最优解。
写法:左指针每次固定右移,右指针往右扩展。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 20;
int n, a[7], b[N];
int cnt[N], q;
void add(int x)
{
++ cnt[x];
if(cnt[x] == 1) ++ q;
}
void rem(int x)
{
-- cnt[x];
if(cnt[x] == 0) -- q;
}
int main()
{
for(int i = 1; i <= 6; ++ i) scanf("%d", &a[i]);
scanf("%d", &n);
for(int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
vector<pii> vec;
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= 6; ++ j)
vec.push_back(make_pair(b[i] - a[j], i));
sort(vec.begin(), vec.end());
int res = 1e9;
int l = 0, r = -1;
while(l < 6 * n)
{
while(r + 1 < 6 * n && q != n) add(vec[++ r].second);
if(q == n) res = min(res, vec[r].first - vec[l].first);
rem(vec[l ++].second);
}
printf("%d
", res);
//system("pause");
return 0;
}
D
给定(n)件物品,价格分别为(1,2,...,n),给定(2 imes n)次操作:
(1:+) 将一件物品放置到货架上
(2: - x) 将物品(x)卖出
卖出物品的规则为每次只能售出价格最低的物品,请根据操作还原放置物品的顺序。
对于每一次卖出,一定是选择最近的最近的放置,这次放置的限制比较小,这样选取答案一定是最优。
使用栈去维护这些操作,每次(+)操作,将这是第几个放入和值的下限(()下限不能被取到()),初始化下限为0.
每次(-)操作,如果栈中已经没有元素或者当前栈顶的下限 (>=)这个值,则不合法,直接输出NO.
如果可以取出,就给栈顶元素位置填上当前取出的数,并对新栈顶修改下限,下限为当前取出的(x)和原来下限的最大值。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 20;
int res[N],cnt;
struct zt
{
int pos, val;
};
stack<zt> s;
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= 2 * n; ++ i)
{
char op[2];
int x;
scanf("%s", op);
if(*op == '+') s.push({++ cnt, 0});
else if(*op == '-')
{
scanf("%d", &x);
if(s.empty() || x <= s.top().val)
{
printf("NO
");
return 0;
}
res[s.top().pos] = x;
s.pop();
if(!s.empty()) s.top().val = max(s.top().val, x);
}
}
printf("YES
");
for(int i = 1; i <= n; ++ i) printf("%d ", res[i]);
puts("");
//system("pause");
return 0;
}
E
每次施放技能,可以对敌人造成(a)点伤害,在接下来的(c)秒时间内,每秒敌人可以恢复(b)点血,技能冷却时间为(d)秒,问可以击杀敌人的最大血量是多少,如果可以击杀任意血量的敌人,输出(-1).
首先考虑输出(-1)的情况,对于一次施放技能来说,如果总恢复血量(b imes c)都不如伤害(a)高,那么显然不论(d)冷却有多久,都可以通过很多次的技能来击杀任意血量的怪物。
故当(a > b imes c) ,答案一定是(-1).
考虑其他情况,当(a >= b imes c),则击杀怪物血量一定有上限,在先不考虑第一次施放技能的前提下,为了求出可以击杀的最大血量,总共可以让怪物恢复的时间为 (t = a / b),在这段时间里,可以施放技能的次数为(k = t / d),加上第一次施放技能总共打掉的血量为(a imes (k + 1)),总共回复的血量为(k imes d imes b + (k - 1) imes d imes b+ ... + d imes b = b imes k imes (k + 1) imes d / 2).
故答案为[ ans = a imes (k + 1) - b imes k imes (k + 1) imes d / 2 ]
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a, b, c, d;
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
if(a > b * c) printf("-1
");
else
{
LL t = a / b;
LL k = t / d;
LL res = a * (k + 1) - b * d * k * (k + 1) / 2;
printf("%lld
", res);
}
}
//system("pause");
return 0;
}
2020.11.17