赞
踩
给 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; }
现在给定 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
如果你有任何建议或者批评和补充,请留言指出,不胜感激
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。