题目链接
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
ll x, y, z, p;
cin >> x >> y >> z >> p;
if (p < x)
swap(x, p);
if (p < y)
swap(y, p);
if (p < z)
swap(z, p);
printf("%I64d %I64d %I64d\n", p - x, p - y, p - z);
return 0;
}
可以将某个数字加一次v或者减一次v不限制操作次数 找到一个最小的v可以将数字变为相同
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
vector<int> v;
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
int x;
cin >> x;
v.push_back(x);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
if (v.size() > 3)
cout << -1 << endl, exit(0);
if (v.size() == 3 && v[1] - v[0] != v[2] - v[1])
cout << -1 << endl, exit(0);
if (v.size() == 3)
cout << v[1] - v[0] << endl;
else if (v.size() == 2)
{
int x = v[1] - v[0];
if (x % 2 == 0)
x /= 2;
cout << x << endl;
}
else
cout << 0 << endl;
return 0;
}
三种食物 告诉你周几吃哪种食物 问从周几出发能够吃的最长时间
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
ll x[3], z[3];
cin >> x[0] >> x[1] >> x[2]; //147 26 35
ll X = min({ x[0] / 3, x[1] / 2, x[2] / 2 }); //整周
x[0] -= X * 3, x[1] -= X * 2, x[2] -= X * 2; //余下物品
ll ans = X * 7;
int y[] = { 0, 1, 2, 0, 2, 1, 0 };
for (int i = 0; i < 7; ++i) //开始
{
z[0] = x[0], z[1] = x[1], z[2] = x[2];
int cnt = 0;
for (int j = i; z[y[j]]--; j = (j + 1) % 7)
cnt++;
ans = max(ans, X * 7 + cnt);
}
cout << ans << endl;
return 0;
}
机器人有普通电池和太阳能充电电池 0为无光1为有光 可以选择消耗一个电池走一步 阳光下可以消耗一个普通电池走一步获得一个充电电池 问最远能走多远
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, a, b; //充电电池 电池
cin >> n >> b >> a;
int A = a, B = b;
for (int i = 1; i <= n; ++i)
{
int s;
scanf("%d", &s);
if (s && B && A < a)
A = min(a, A + 1), --B;
else if (A)
--A;
else
--B;
if (!A && !B)
cout << i << endl, exit(0);
}
cout << n << endl;
return 0;
}
两个教练选人 每次选数值最大的并且将旁边的k个也选走 问每个人都被那个教练选走了
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int l[N], r[N]; //左侧右侧编号
int a[N], b[N], c[N]; //b表示a数组从大到小编号
void sel(int x, int p) //选中x
{
r[l[x]] = r[x], l[r[x]] = l[x]; //拼接lr
c[x] = p; //记录结果
}
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]), l[i] = i - 1, r[i] = i + 1, b[i] = i;
sort(b + 1, b + n + 1, [](int x, int y) { return a[x] > a[y]; });
int p = 1;
for (int i = 1; i <= n; ++i) //从大到小选取
{
if (c[b[i]]) //已经被选
continue;
int k = l[b[i]]; //两侧坐标
for (int j = 0; k && j < m; ++j)
sel(k, p), k = l[k];
k = r[b[i]];
for (int j = 0; k && j < m; ++j)
sel(k, p), k = r[k];
sel(b[i], p);
p = p == 1 ? 2 : 1;
}
for (int i = 1; i <= n; ++i)
putchar('0' + c[i]);
cout << endl;
return 0;
}
写丑了的map版
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
bool one[N]; //是否1队
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
map<int, int> pos, val; //位置顺序 值顺序
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i)
{
int v;
scanf("%d", &v);
pos[i] = v;
val[v] = i;
}
int flag = 1;
while (!val.empty())
{
int p = val.rbegin()->second; //最大值位置
for (int i = 0; i < k; ++i) //左侧
{
auto it = pos.lower_bound(p);
if (it == pos.begin())
break;
--it;
if (flag) one[it->first] = 1;
val.erase(it->second);
pos.erase(it);
}
for (int i = 0; i < k; ++i) //右侧
{
auto it = pos.upper_bound(p);
if (it == pos.end())
break;
if (flag) one[it->first] = 1;
val.erase(it->second);
pos.erase(it);
}
if (flag) one[p] = 1;
val.erase(pos[p]);
pos.erase(p);
flag ^= 1;
}
for (int i = 1; i <= n; ++i)
putchar(one[i] ? '1' : '2');
cout << endl;
return 0;
}
n个物品买k个 有m个优惠每买x个物品其中y个就免费 问最小费用
如果买k个不管有没有优惠肯定买最便宜的k个,每个优惠策略可以重复使用所以如果同样是买x个一个优惠y1一个优惠y2则取最大的。
购买使用优惠时肯定是将大小相近的作为一组一起购买,因为尽量优惠较大的。进行排序(其实找到前k小已经排序了)。
令f[i]表示购买前i个的最小代价,枚举已经购买的物品数量尝试使用每个优惠进行转移取最小值。
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int a[N], b[N], s[N];
int f[N]; //买前i个物品的最小代价
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1); //贪心选择尽量便宜的k个 并且dp过程中需要价值连续
for (int i = 1; i <= k; ++i)
s[i] = s[i - 1] + a[i]; //前缀和优化转移
for (int i = 0; i < m; ++i)
{
int x, y; //买x免费y
scanf("%d%d", &x, &y);
b[x] = max(b[x], y); //尽量多
}
memset(f, 0x3f, sizeof(f));
f[0] = 0; //没有物品代价0
for (int i = 1; i <= k; ++i) //物品
for (int j = 1; j <= i; ++j) //一次性购买量
f[i] = min(f[i], f[i - j] + s[i] - s[i - j + b[j]]); //只花费后半部分
cout << f[k] << endl;
return 0;
}
任选两个数字 求最小的最小公倍数
记录每个数字出现次数和出现下标,暴力枚举公因子i并乘上倍数j查询数值是否出现,如果同一个公因子i有两个倍数j出现则计算答案并且break,因为后面会更大。
即使是极端情况复杂度也在1e8以内。
#include
#include
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e7 + 10;
int cnt[N], pos[N]; //数值出现次数 数值编号
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n;
cin >> n;
ll ans = LINF, p, q;
for (int i = 1; i <= n; ++i)
{
int x;
scanf("%d", &x);
++cnt[x];
if (cnt[x] > 1 && ans > x) //出现2次可以直接作为答案
ans = x, p = pos[x], q = i; //记录上次的编号和i
pos[x] = i;
}
for (int i = 1; i < N; ++i) //公约数
{
int k = 0; //当前公约数最小的数字的倍率
for (int j = 1; i * j < N; ++j) //倍率
if (cnt[i * j])
{
if (k) //之前已有一个
{
if (ans > 1LL * i * j * k) //公约数*两个数的倍
ans = 1LL * i * j * k, p = pos[i * k], q = pos[i * j]; //记录编号
break; //后面只会更大
}
else
k = j; //记录倍率
}
}
if (p > q)
swap(p, q);
cout << p << " " << q << endl;
return 0;
}