A: Life of a Flower
题意
有一朵初始高度为
1
1
1 的花,它第
i
i
i 天的成长状态如下:
- 如果第
i
i
i 与
i
?
1
i-1
i?1 连续两天都没有浇水,它会枯死
- 如果第
i
i
i 天浇水(但是第
i
?
1
i-1
i?1 天未浇水),它会长高
1
c
m
1cm
1cm
- 如果第
i
i
i 与
i
?
1
i-1
i?1 连续两天都浇水,它会长高
5
c
m
5cm
5cm
- 如果第
i
i
i 天没有浇水,它不会成长
现给出
n
n
n 天的浇水状况,求花的最终高度,若中途枯死则输出
?
1
-1
?1
题解
根据题意模拟即可
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){
x=0;
char c=getchar(),last=' ';
while(!isdigit(c))last=c,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(last=='-')x=-x;
}
const int MAXN=1e2+5;
int n;
int a[MAXN];
int main()
{
int T;read(T);
while(T--){
read(n);
int ans=1;
for(int i=1;i<=n;i++){
read(a[i]);
if(ans==-1)continue;
if(a[i]){
if(a[i-1])ans+=5;
else ans++;
}
else{
if(i>1&&a[i-1]==0)ans=-1;
}
}
cout<<ans<<'\n';
}
return 0;
}
B: Array Eversion
题意
给出一个长度为
n
n
n 的数组
a
a
a,定义一种操作如下:
- 令
x
=
a
n
x=a_n
x=an?
- 将数组分类为两个部分,左部分包含
a
i
≤
x
a_i\le x
ai?≤x 的元素,右部分包含
a
i
>
x
a_i>x
ai?>x 的元素,各部分内元素顺序与原数组顺序一致
- 将左右部分合并,即为操作后的新数组
可以证明在有限次操作后,数组将不会变化(即再进行操作得到的新数组不变) 求可以使得数组变为不变状态的最小操作次数
题解
Lemma1:当
a
n
≥
a
i
(
1
≤
i
≤
n
)
a_n\ge a_i(1\le i\le n)
an?≥ai?(1≤i≤n) ,即
a
n
a_n
an? 为数组中最大元素时,数组不会被操作改变
Lemma2:一次操作后,
i
i
i 最大的
a
i
>
x
(
a
n
)
a_i>x(a_n)
ai?>x(an?) 会成为新的
a
n
a_n
an?
从
n
n
n ~
1
1
1 扫描一次数组,每次扫到一个
a
i
>
a
n
a_i>a_n
ai?>an? 时将
a
i
a_i
ai? 替换为新的
a
n
a_n
an? ,操作数+1即可
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){
x=0;
char c=getchar(),last=' ';
while(!isdigit(c))last=c,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(last=='-')x=-x;
}
const int MAXN=2e5+5;
int n;
int a[MAXN];
int main()
{
int T;read(T);
while(T--){
read(n);
for(int i=1;i<=n;i++)read(a[i]);
int ans=0;
for(int i=n-1,last=a[n];i>=1;i--){
if(a[i]>last){
ans++;
last=a[i];
}
}
cout<<ans<<'\n';
}
return 0;
}
C: Minimize Distance
题意
在数轴上有
n
n
n 个仓库,第
i
i
i 个仓库位于
x
i
x_i
xi? 处 在原点上有
n
n
n 件货物(没有货物时要回原点拿),一位商人从原点出发,他同时最多可以带
k
k
k 件货物,当他经过一个仓库时,他就可以将一件带着的货物放入仓库中 求将
n
n
n 件货物放入
n
n
n 个仓库中,商人所需行走的最短路程(注意最终完成任务时商人不必回到原点)
题解
首先我们将正负数分开处理(因为在原点的不同方向上) 对于同一方向上的任务,我们采用贪心,每次送最远的
k
k
k 个仓库(若不足则将该方向上全部送完),代价是所送仓库中
m
a
x
(
∣
x
i
∣
)
×
2
max(|x_i|)\times 2
max(∣xi?∣)×2 (因为要走来回所以要乘
2
2
2 ) 最后减去所有仓库中
m
a
x
(
∣
x
i
∣
)
max(|x_i|)
max(∣xi?∣) 即可(显然最后停留在这个点不回原点可以减少最多的代价)
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){
x=0;
char c=getchar(),last=' ';
while(!isdigit(c))last=c,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(last=='-')x=-x;
}
const int MAXN=2e5+5;
int n,k;
int ca,cb;
long long a[MAXN],b[MAXN];
long long ans;
int main()
{
int T;read(T);
while(T--){
read(n),read(k);
ca=cb=1;
for(int i=1,x;i<=n;i++){
read(x);
if(x>0)a[ca++]=x;
else b[cb++]=x;
}ca--,cb--;
sort(a+1,a+ca+1);
sort(b+1,b+cb+1,greater<int>());
ans=-max(a[ca],-b[cb]);
for(int i=ca;i>=1;i-=k)ans+=2*a[i];
for(int i=cb;i>=1;i-=k)ans-=2*b[i];
cout<<ans<<'\n';
}
return 0;
}
D: Yet Another Sorting Problem
题意
给定一个长度为
n
n
n 的数组
a
a
a ,我们有以下交换规则:
- 选定
3
3
3 个互不相同的位置
i
,
j
,
k
i,j,k
i,j,k
- 将
a
i
,
a
j
,
a
k
a_i,a_j,a_k
ai?,aj?,ak? 分别变为
a
j
,
a
k
,
a
i
a_j,a_k,a_i
aj?,ak?,ai?
问只使用这种交换方式,能否使得整个数组变为不降的
题解
Lemma1:(参考样例
3
3
3 )如果有两个元素相同,我们定然可以排序使得整个数组不降 证明: 令四个元素为
a
,
a
,
x
,
y
a,a,x,y
a,a,x,y 先交换前
3
3
3 个元素,得
a
,
x
,
a
,
y
a,x,a,y
a,x,a,y 再交换后
3
3
3 个元素,得
a
,
a
,
y
,
x
a,a,y,x
a,a,y,x 显然,我们在不调整其他元素的条件下实现了
x
,
y
x,y
x,y 两个元素的互换 既然可以实现任意两个元素的交换,那么排序显然可行
Lemma2:如果整个数组是一个排列(即:没有元素相同),那么可以排序的充要条件是:原排列为偶排列 略证: 设在目标排列中有3个元素
a
i
,
a
j
,
a
k
(
i
<
j
<
k
,
a
i
<
a
j
<
a
k
)
a_i,a_j,a_k(i<j<k,a_i<a_j<a_k)
ai?,aj?,ak?(i<j<k,ai?<aj?<ak?) 那么此时,对于这三个元素而言,逆序数为
0
0
0(偶) 对这
3
3
3 个元素使用一次交换,得到的结果只会是
a
j
,
a
k
,
a
i
a_j,a_k,a_i
aj?,ak?,ai? (逆序数为
2
2
2 (偶) ,分别是
a
j
,
a
i
a_j,a_i
aj?,ai? 和
a
k
,
a
i
a_k,a_i
ak?,ai? )或
a
k
,
a
i
,
a
j
a_k,a_i,a_j
ak?,ai?,aj? (逆序数为
2
2
2 (偶) ,分别是
a
k
,
a
i
a_k,a_i
ak?,ai? 和
a
k
,
a
j
a_k,a_j
ak?,aj? ) (考虑上其他元素,排列的奇偶性也不会改变,但是我懒得写了XD) 所以该种交换不会改变排列的奇偶性,那么若原排列的奇偶性与目标排列相同(目标排列的逆序数为
0
0
0 ,因此原排列应为偶排列),那么我们一定可以通过某种方式交换得到目标排列
我们先判是否有重复元素,有则直接输出
Y
E
S
YES
YES ,否则检查排列奇偶性即可(我使用了归并排序来求逆序数)
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){
x=0;
char c=getchar(),last=' ';
while(!isdigit(c))last=c,c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(last=='-')x=-x;
}
const int MAXN=5e5+5;
int n;
int a[MAXN],tmp[MAXN];
bitset<MAXN>vis;
long long merge_sort(int l,int r){
if(l>=r)return 0;
int mid=l+r>>1;
long long ret=merge_sort(l,mid)+merge_sort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]<=a[j])tmp[k++]=a[i++];
else{
ret+=mid-i+1;
tmp[k++]=a[j++];
}
}
while(i<=mid)tmp[k++]=a[i++];
while(j<=r)tmp[k++]=a[j++];
for(int i=l;i<=r;i++)a[i]=tmp[i];
return ret;
}
int main()
{
int T;read(T);
while(T--){
read(n);
for(int i=1;i<=n;i++)read(a[i]);
vis.reset();
int ok=0;
for(int i=1;i<=n;i++){
if(vis[a[i]])ok=1;
vis[a[i]]=1;
}
if(ok)puts("YES");
else puts(merge_sort(1,n)&1?"NO":"YES");
}
return 0;
}
|