E - Minimal payments
题意:
给定
n
n
n 种货币,
a
1
=
1
,
a
i
<
a
i
+
1
a_1=1,a_i<a_{i+1}
a1=1,ai<ai+1,并且保证了
a
i
+
1
%
a
i
=
0
a_{i+1} \ \% \ a_i = 0
ai+1 % ai=0
给出
X
X
X 元,要求给定支付的货币数量与找零货币数量之和最小
思路:
数据很小,考虑记忆化搜索,贪心的从大货币开始遍历
假设当前是
x
x
x 元,枚举到了第
i
i
i 个货币
我们拿出
⌊
x
a
i
⌋
\lfloor\frac{x}{a_i}\rfloor
⌊aix⌋ 张,剩下
x
%
a
i
x \ \% \ a_i
x % ai 元
或者拿出
⌊
x
a
i
⌋
+
1
\lfloor\frac{x}{a_i}\rfloor+1
⌊aix⌋+1 张,多出来的找零
m
a
p
map
map 套
m
a
p
map
map 搞一个记忆化数组
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 1e2 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
ll a[maxn];
map <ll, map<int, ll> > f;// 记忆化数组
ll dfs(ll x, int i){
if(i == 1) return x;
if(f[x][i]) return f[x][i];
ll res = x / a[i];
ll w1 = res + dfs(x % a[i], i - 1);
ll w2 = res + 1 + dfs((res + 1) * a[i] - x, i - 1);
f[x][i] = min(w1, w2);
return f[x][i];
}
void work()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i) cin >> a[i];
cout << dfs(m, n) << endl;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}
F - Jealous Two
题意:
给定两个长度为
n
n
n 的序列
a
,
b
a,b
a,b,问有多少对
(
i
,
j
)
(i,j)
(i,j) 满足
a
i
>
=
a
j
,
b
i
<
=
b
j
a_i>=a_j,b_i<=b_j
ai>=aj,bi<=bj
a
i
,
b
i
<
=
1
0
9
a_i,b_i<=10^9
ai,bi<=109
思路:
显然是二维偏序
首先对
b
b
b 数组排序,消除第二个限制。
然后就变成了求
a
a
a 数组的类似逆序对的问题。
不同是逆序对是找
i
<
j
,
a
i
>
a
j
i<j,a_i>a_j
i<j,ai>aj,而我们需要找
i
<
j
,
a
i
>
=
a
j
i<j,a_i>=a_j
i<j,ai>=aj
重复元素需要加入贡献
求逆序数加强版
这道题是有相同数据不计贡献,处理方法稍加修改即可变成计贡献
具体操作就是:对
a
a
a 按照
x
<
x<
x< 为第一关键字排序,
i
d
>
id >
id> 为第二关键字排序,然后
R
a
n
k
[
d
[
i
]
.
i
d
]
=
i
Rank[d[i].id] = i
Rank[d[i].id]=i 构造一个新序列,上树状数组求解即可
为什么这样就对呢?
这时候我们看相同的数据发生了什么,一组相同的数据,本来排在后边的
i
d
id
id 大,然后排序时被排到了前边,在它原来位置赋给它的
i
i
i 就小,这样一组相同的数据就出现了这样的状况:从
1
1
1 到
n
n
n,相同的数据赋予的
i
i
i 总是严格递减的,这样就会产生逆序数,就满足了我们要求相同时也计数的要求
但是还有有两点要注意:
当
i
=
j
i=j
i=j 时方案合法,所以最后的答案要
+
n
+n
+n
当两个物品的两个值都相同是
(
x
,
y
)
,
(
x
,
y
)
(x,y),(x,y)
(x,y),(x,y) 时,不仅
(
i
,
j
)
(i,j)
(i,j) 有贡献
(
j
,
i
)
(j,i)
(j,i) 也有贡献,在外面单独统计一下即可。
时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
参考题解
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
struct node{
int x, y;
bool operator<(const node &B){
return (y < B.y || y == B.y && x > B.x);
}
}a[maxn];
int c[maxn];
void update(int i, int k){
while(i <= n) c[i] += k, i += i & (-i);
}
int qry(int i){
ll ans = 0;while(i) ans += c[i], i -= i & (-i);
return ans;
}
int Rank[maxn];
struct Node{
int x, id;
bool operator<(const Node &B){
return (x < B.x || x == B.x && id > B.id);
}
}d[maxn];
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i].x;
for(int i = 1; i <= n; ++i) cin >> a[i].y;
sort(a + 1, a + 1 + n);
ll ans = 0, cnt = 1;
for(int i = 1; i <= n; ++i){// 单独统计特殊情况
if(a[i].x != a[i+1].x || a[i].y != a[i+1].y)
ans += cnt * (cnt - 1) / 2, cnt = 1;
else ++cnt;
}
for(int i = 1; i <= n; ++i) d[i].x = a[i].x, d[i].id = i;
sort(d + 1, d + 1 + n);
for(int i = 1; i <= n; ++i) Rank[d[i].id] = i;
for(int i = 1; i <= n; ++i){
ans += i - 1 - qry(Rank[i] - 1);
update(Rank[i], 1ll);
}
cout << ans + n;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}
496

被折叠的 条评论
为什么被折叠?



