B. Meeting on the Line
题意:有
n
n
n个人,第
i
i
i个人在
x
i
x_i
xi位置,出门需要花
t
i
t_i
ti时间打扮,故第
i
i
i个人去某地
x
x
x需要花费
a
b
s
(
x
−
x
i
)
+
t
i
abs(x-x_i)+t_i
abs(x−xi)+ti,让你求一个相聚位置
x
x
x,使得所有人聚集的时间最小。
思路:
方法一:二分让所有人聚集的时间。详情看官方题解。
方法二:假设相聚位置为
x
x
x,那么对于位置在
x
x
x的左侧的人的花费是
x
−
x
i
+
t
i
x-x_i+t_i
x−xi+ti,对于位置在
x
x
x的右侧的人的花费是
x
i
−
x
+
t
i
x_i-x+t_i
xi−x+ti,可以维护出两个数组
a
,
b
a,b
a,b,数组
a
a
a表示
t
i
−
x
i
t_i-x_i
ti−xi的前缀最大值,数组
b
b
b表示
x
i
+
t
i
x_i+t_i
xi+ti的后缀最大值,在位置
[
x
i
,
x
i
+
1
]
[x_i,x_{i+1}]
[xi,xi+1]中选取一个位置
x
x
x,使得
m
a
x
(
a
[
i
]
+
x
,
b
[
i
+
1
]
−
x
)
max(a[i]+x,b[i+1]-x)
max(a[i]+x,b[i+1]−x)最小,不难想到
x
=
m
i
n
(
x
[
i
+
1
]
,
m
a
x
(
(
b
[
i
+
1
]
−
a
[
i
]
)
/
2
,
x
[
i
]
)
)
x=min(x[i+1],max((b[i+1]-a[i])/2,x[i]))
x=min(x[i+1],max((b[i+1]−a[i])/2,x[i]))。
方法三:将点
(
x
i
,
t
i
)
(x_i,t_i)
(xi,ti)转化为两点
(
x
i
−
t
i
,
0
)
(x_i-t_i,0)
(xi−ti,0)和
(
x
i
+
t
i
,
0
)
(x_i+t_i,0)
(xi+ti,0),答案就是(最大坐标+最小坐标)/2。证明见官方题解。
方法二代码:
#include <bits/stdc++.h>
using namespace std;
#define il inline
#define pb push_back
#define fi first
#define se second
#define int long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=1e-9;
const int mod=1e7+7;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
int T,n;
double x[N],t[N],a[N],b[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
// T=1;
while(T--){
cin>>n;
map<double,double> mp;
for(int i=1;i<=n;++i) {
cin>>x[i];
}
double tt;
for(int i=1;i<=n;++i) {
cin>>tt;
mp[x[i]]=max(mp[x[i]],tt);
}
if(mp.size()==1){
for(auto tmp:mp) cout<<fixed<<setprecision(8)<<tmp.fi<<'\n';
}else{
int cnt=0;
for(auto tmp:mp){
x[++cnt]=tmp.fi;
t[cnt]=tmp.se;
}
a[0]=0-1000000000.0;
b[cnt+1]=0;
for(int i=1;i<=cnt;++i)
a[i]=max(t[i]-x[i],a[i-1]);
for(int i=cnt;i>=1;--i)
b[i]=max(t[i]+x[i],b[i+1]);
double mi=1000000005.0,ans=x[1];
for(int i=1;i<cnt;++i) {
double pos=(b[i+1]-a[i])/2;
if(pos<=x[i]) pos=x[i];
else if(pos>=x[i+1]) pos=x[i+1];
if(max(a[i]+pos,b[i+1]-pos)<mi) {
mi=max(a[i]+pos,b[i+1]-pos);
ans=pos;
}
}
cout<<fixed<<setprecision(8)<<ans<<'\n';
}
}
}
方法三代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int T,n;
double x[N],t[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;++i) cin>>x[i];
for(int i=1;i<=n;++i) cin>>t[i];
double mi=1000000000.0,mx=0-1000000000.0;
for(int i=1;i<=n;++i) {
mi=min(x[i]-t[i],mi);
mx=max(mx,x[i]+t[i]);
}
double ans=(mi+mx)/2;
cout<<fixed<<setprecision(8)<<ans<<'\n';
}
}
C. Minimum Notation
题意:给你一个字符串。操作:选择串中的一个数d,把它删掉,然后在任意一个位置插入min(9,d+1)。操作可以重复0次或若干次,问最终能得到的最小的字符串是什么。
思路:倒着遍历串,并记录遍历到的数字中的最小数
m
i
mi
mi,如果当前数
d
d
d大于
m
i
mi
mi,那么毫无疑问,将该数变为min(9,d+1)插到后面会更优,因为这样使整个串保持非递减状态。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
int T;
string s;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>s;
map<char,int> mp;
char mi=s[s.size()-1];
for(int i=s.size()-1;i>=0;--i){
if(s[i]>mi){
if(s[i]<'9') mp[s[i]+1]++;
else mp[s[i]]++;
}else{
mp[s[i]]++;
mi=s[i];
}
}
for(auto x:mp){
for(int i=1;i<=x.se;++i) cout<<x.fi;
}
cout<<'\n';
}
}
D. Prefixes and Suffixes
题意:给定两个长度为
n
n
n的字符串
s
1
,
s
2
s1,s2
s1,s2。操作:选一个
k
,
(
1
≤
k
≤
n
)
k,(1\le k\le n)
k,(1≤k≤n),交换
s
1
s1
s1长度为
k
k
k的前缀和
s
2
s2
s2长度为
k
k
k的后缀。操作次数不限。问通过若干次变化,是否可以得到两个一样的串。
思路:一整块交换,等价于,若干次一个元素对一个元素的交换。相互交换的元素不能在同一个串中出现,它们构成了一个交换对。长度为
n
n
n的两个串,构成了
n
n
n对交换对(无序)。交换对中的两个元素属于不同的串。当交换对中的其中一个元素的位置确定,那么另一个元素的位置也确定。关系是假设一个元素在第一个串的位置是
i
i
i,那么在另一个元素在第二个串的位置是
n
−
i
−
1
n-i-1
n−i−1,因为它们是一对交换对,必须是这样的位置关系。所以,先统计一下每种交换对的个数,满足 同种交换对的个数是偶数或者个数是奇数的交换对只有一种并且两个元素是相同的,那么就“YES”,否则“NO”。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define se second
#define fi first
int T,n;
string s1,s2;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>s1>>s2;
string str="";
map<string,int> mp;
for(int i=0,j=n-1;i<n;i++,j--){
str="";
if(s1[i]>s2[j]) {
str+=s2[j];
str+=s1[i];
}else {
str+=s1[i];
str+=s2[j];
}
mp[str]++;
}
int cnt=0;
for(auto x:mp){
if(x.se%2) {
if(x.fi[0]!=x.fi[1]){
cnt=2;
break;
}else cnt++;
}
}
if(cnt<2) cout<<"YES\n";
else cout<<"NO\n";
}
}