AtCoder Beginner Contest 231(EF补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 231(EF补题)相关的知识,希望对你有一定的参考价值。
E - Minimal payments
题意:
给 N N N种面值的钱币,现在需要支付 X X X元,现在定义 A A A为支付的钞票数, B B B为找钱找回来的钞票数,问 A + B A+B A+B最小是多少?
思路:
直接记忆化搜索,金额较大,所以开
m
a
p
map
map
定义
f
(
n
,
x
)
f(n,x)
f(n,x)为前
n
n
n种钞票支付
x
x
x元的情况下,最小的
A
+
B
A+B
A+B
那么此时为了让
A
+
B
A+B
A+B最小,一定是尽可能用大钞票,所以
f
(
n
,
x
)
=
f
(
n
−
1
,
x
%
a
[
n
]
)
+
x
/
a
[
n
]
f(n,x)=f(n-1,x \\%a[n])+x/a[n]
f(n,x)=f(n−1,x%a[n])+x/a[n],代表尽可能的用
a
[
n
]
a[n]
a[n]这种钞票,使得用前
n
−
1
n-1
n−1种钱,解决剩下的钱。
如果
x
%
a
[
n
]
=
0
x\\%a[n]=0
x%a[n]=0,那么说明不需要找钱,所以就不需要第二种策略了
反之可能需要第二种策略
即
f
(
n
,
x
)
=
f
(
n
−
1
,
a
[
n
]
−
(
x
%
a
[
n
]
)
)
+
x
/
a
[
n
]
+
1
f(n,x)=f(n-1,a[n]-(x\\%a[n]))+x/a[n]+1
f(n,x)=f(n−1,a[n]−(x%a[n]))+x/a[n]+1,这个的含义就是多给一张
a
[
n
]
a[n]
a[n]这种金额的钱,前
n
−
1
n-1
n−1种钱来解决剩下的钱。
所以就是上述两种策略的最小值
#include<bits/stdc++.h>
using namespace std;
const int N=70;
using ll = long long ;
ll n,x;
ll a[N];
map<int,ll> f[N];
ll dfs(int n,ll x)
if(n==1)
return x;
if(x==0)
return 0;
if(f[n].find(x)!=f[n].end())
return f[n][x];
f[n][x]=dfs(n-1,x%a[n])+x/a[n];
if(x%a[n])
f[n][x]=min(f[n][x],dfs(n-1,a[n]-(x%a[n]))+x/a[n]+1);
return f[n][x];
int main()
cin>>n>>x;
for(int i=1;i<=n;i++)
cin>>a[i];
cout<<dfs(n,x)<<endl;
F - Jealous Two
题意:
现在给定 N N N个物品,有 2 2 2个人,对每种物品的评价分别为 A i A_i Ai和 B i B_i Bi,让你求 ∑ i = 1 n ∑ j = 1 n [ A i ≥ A j & & ≤ B i ≤ B j ] \\sum \\limits_i=1 ^n\\sum \\limits_j=1 ^n[A_i≥A_j\\&\\&≤B_i≤B_j] i=1∑nj=1∑n[Ai≥Aj&&≤Bi≤Bj]
思路:
可以用所有情况,即
N
2
N^2
N2减去不符合的情况数量
不符合的情况就是
A
i
<
A
j
∣
∣
B
i
>
B
j
A_i<A_j||B_i>B_j
Ai<Aj∣∣Bi>Bj
那么就直接找
A
i
<
A
j
A_i<A_j
Ai<Aj的数量和
B
i
>
B
j
B_i>B_j
Bi>Bj的数量,再次减去
A
i
<
A
j
&
&
B
i
>
B
j
A_i<A_j\\&\\&B_i>B_j
Ai<Aj&&Bi>Bj的数量(因为算重了,容斥)
前面两种数量直接排完序后,直接计数即可
最后一种情况利用树状数组来求即可,就类似于求逆序对的数量。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
#define ll long long
struct node
int x;
int id;
bool operator<(const node &t) const return x < t.x;
a[N], b[N];
int n;
int A[N], B[N];
int tr[N];
int lowbit(int x) return x & (-x);
void Insert(int x)
for (int i = x; i <= n; i += lowbit(i))
tr[i]++;
int Query(int x)
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += tr[i];
return res;
int main()
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].x;
a[i].id = i;
sort(a + 1, a + n + 1);
int cnt = 0;
for (int i = 1; i <= n; i++)
if (i == 1 || a[i].x != a[i - 1].x)
cnt++;
A[a[i].id] = cnt;
for (int i = 1; i <= n; i++)
cin >> b[i].x;
b[i].id = i;
sort(b + 1, b + n + 1);
cnt = 0;
for (int i = 1; i <= n; i++)
if (i == 1 || b[i].x != b[i - 1].x)
cnt++;
B[b[i].id] = cnt;
ll res = 0;
int r = n;
while (r)
int l = r;
for (; l && a[l].x == a[r].x; l--)
res += n - r;
r = l;
r = n;
while (r)
int l = r;
for (; l&&b[l].x == b[r].x; l--)
res += n - r;
r = l;
r = n;
while (r)
int l = r;
for (; l&&a[l].x == a[r].x; l--)
res -= Query(B[a[l].id] - 1);
l = r;
for (; l&&a[r].x == a[l].x; l--)
Insert(B[a[l].id]);
r = l;
printf("%lld\\n", 1ll * n * n - res);
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于AtCoder Beginner Contest 231(EF补题)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解