A. Planets
题意:
轨道上有很多星星,可以花费代价 1 1 1 摧毁一颗星星,也可以花费代价 c c c 摧毁一个轨道上的所有星星。询问摧毁所有星星的最小代价
解析:
贪心。每个轨道上星星数目 c n t i cnt_i cnti 是否大于 c c c。大于 c c c ,花费代价 c c c 一次摧毁;不大于 c c c ,花费 c n t i cnt_i cnti 代价摧毁。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int n, c;
vector<int> a[maxn];
void solve(){
cin >> n >> c;
for(int i = 0; i <= 100; i++)
a[i].clear();
for(int i = 1; i <= n; i++){
int x;
cin >> x;
a[x].push_back(i);
}
ll ans = 0;
for(int i = 0; i <= 100; i++){
int sum = a[i].size();
/*for(int j = 0; j < a[i].size(); j++){
sum += a[i][j];
}*/
if(sum > c)
ans += c;
else
ans += sum;
}
//cout << "ans = ";
cout << ans << endl;
return;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}
B. Meeting on the Line
题意:
n n n 个人在一维直线上,第 i i i的人坐标为 x i x_i xi,到达坐标 x 0 x_0 x0 花费的时间为: t i + ∣ x i − x 0 ∣ t_i+|x_i-x_0| ti+∣xi−x0∣。询问 x 0 x_0 x0,使 max 1 ≤ i ≤ n { t i + ∣ x i − x 0 ∣ } \max\limits_{1\le i \le n}\{t_i+|x_i-x_0|\} 1≤i≤nmax{ti+∣xi−x0∣} 最小
解析:
三分坐标。对坏点来说,好点和最优点在同一侧。
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
有无大佬教教为什么
const double eps = 1e-8;
while(r-l > eps)
这样T了,改成循环50次过的。
也可以二分时间,每个人能到的范围求交集,交集为一个点时,该点为最优解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
db x[maxn], t[maxn];
int n;
db check(double a){
db tim = 0;
for(int i = 1; i <= n; i++){
tim = max(tim, t[i]+fabs(x[i]-a));
}
return tim;
}
void solve(){
cin >> n;
db l = INF, r = -1;
for(int i = 1; i <= n; i++){
cin >> x[i];
l = min(l, x[i]);
r = max(r, x[i]);
}
for(int i = 1; i <= n; i++)
cin >> t[i];
db ans = x[1];
/*if(fabs(r-l) < eps)
ans = x[1];*/
int cnt = 0;
while(1){
++cnt;
if(cnt > 50)
break;
db x1 = l + (r-l)/3;
db x2 = r-(r-l)/3;
db res1 = check(x1);
db res2 = check(x2);
if(res1 < res2){
r = x2;
ans = x1;
}
else{
l = x1;
ans = x2;
}
}
//cout << "ans = ";
cout << setprecision(10) << ans << endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
C. Minimum Notation
题意:
给定由数字0-9构成的字符串,每次操作是:删除一个数 d d d,然后在任意位置插入 m i n ( d + 1 , 9 ) min(d+1, 9) min(d+1,9),操作次数无限。询问得到的最小字典序的串。
解析:
如果这个串不是递增的,即存在
i
i
i,满足
a
i
>
a
i
+
1
a_i > a_{i+1}
ai>ai+1,删除
a
i
a_i
ai,在
a
i
+
1
a_{i+1}
ai+1后面某个位置插入
a
i
+
1
a_i+1
ai+1一定会更优。
如果这个串是递增的,即
a
i
≤
a
i
+
1
a_i \le a_{i+1}
ai≤ai+1,删除一定不会变优。
所以最终的串一定是递增的。遍历一遍,统计每个数出现的次数,对于需要删除的数
a
i
a_i
ai,对
a
i
+
1
a_{i}+1
ai+1的次数贡献。然后从0-9输出即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
string s;
int num1[15], num2[15];
int vis[maxn];
void solve(){
cin >> s;
memset(num1, 0, sizeof(num1));
memset(num2, 0, sizeof(num2));
for(int i = 0; i <= s.length(); i++)
vis[i] = 0;
for(int i = s.length()-1; i >= 0; i--){
int a = s[i]-'0';
num1[a]++;
if(a == 0)
continue;
for(int j = a-1; j >= 0; j--){
if(num1[j] > 0){
vis[i] = 1;
break;
}
}
}
for(int i = 0; i < s.length(); i++){
int a = s[i]-'0';
if(vis[i])
num2[min(a+1, 9)]++;
else
num2[a]++;
}
for(int i = 0; i <= 9; i++){
for(int j = 1; j <= num2[i]; j++)
cout << i;
}
cout << endl;
return ;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}
D. Prefixes and Suffixes
题意:
给定长度为 n n n 的两个字符串 a , b a,b a,b ,每次操作:选定 k k k, ( 1 ≤ k ≤ n ) (1 \le k \le n) (1≤k≤n),交换长度为 k k k 的 a a a 的前缀 与 长度为 k k k 的 b b b 的后缀。操作次数无线,询问两个串能否相同。
解析:
注意到,无论怎么交换,
a
i
a_i
ai 和
b
n
−
i
b_{n-i}
bn−i总是分别在两个串中,而且
a
i
a_i
ai到串首的距离总是等于
b
n
−
i
b_{n-i}
bn−i到串位的距离,如果将串
b
b
b翻转,则
a
i
a_i
ai 和
b
n
−
i
b_{n-i}
bn−i总是在相同位置,将
a
i
a_i
ai 和
b
n
−
i
b_{n-i}
bn−i看成一个无序对
c
i
c_i
ci。可以证明,通过操作,
c
c
c能够以任意顺序排列 。
对于位置
i
,
j
(
j
≤
i
)
i,j(j \le i)
i,j(j≤i)。令
k
=
j
k=j
k=j,将
c
j
c_j
cj放到序列首。令
k
=
1
k=1
k=1,可以交换
c
c
c中
a
a
a与
b
b
b字符的位置,所以
c
c
c是无序对。令
k
=
i
k=i
k=i,将序列首的
c
j
c_j
cj放到位置
i
i
i。对于以上三次(或者两次)操作,将
c
j
c_j
cj放到
i
i
i位置上,且不影响
i
+
1
i+1
i+1到
n
n
n位置上的
c
c
c。
因此,只需要判断
c
c
c能够构成逆序对,如果能构成回文,则两个串可以相同;反之不能。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
int cnt[30][30];
string a, b;
int n;
void solve(){
memset(cnt, 0, sizeof(cnt));
cin >> n >> a >> b;
for(int i = 0; i < n; i++){
int x = a[i]-'a';
int y = b[n-i-1]-'a';
if(x > y)
swap(x, y);
cnt[x][y]++;
}
for(int i = 0; i < 26; i++){
for(int j = i+1; j < 26; j++){
if(cnt[i][j]%2){
cout << "NO" << endl;
return;
}
}
}
int sum = 0;
for(int i = 0; i < 26; i++){
sum += cnt[i][i]%2;
}
if(sum > n%2){
cout << "NO" << endl;
return;
}
cout << "YES" << endl;
return;
}
int main(){
int T;
cin >> T;
while(T--)
solve();
return 0;
}