本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Educational Codeforces Round 121 (Rated for Div. 2)A-D题解
A. Equidistant Letters
一个字符串,要求让相同字母之间的距离相等,重新排列这些字母
找到相同的字母,相同的字母先排一遍,然后再按第一次排的顺序排一遍。
独有的字母就排在后面就行
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 1e5+5;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
vector<int>cnt(26);
char s[55];
scanf("%s",s);
for(int i=0;i<strlen(s);i++)
cnt[s[i]-'a']++;
vector<int>a,b;
for(int i=0;i<26;i++)
{
if(cnt[i]==2) a.push_back(i);
else if(cnt[i]==1) b.push_back(i);
}
for(auto i : a) cout<<(char)(i+'a');
for(auto i : a) cout<<(char)(i+'a');
for(auto i : b) cout<<(char)(i+'a');
cout<<endl;
}
return 0;
}
B. Minor Reduction
一个数字,可以做一个操作:对相邻的两个数字做加和操作,加和的结果替代这两个数字,求可以形成的最大结果是多少?
考虑几种情况:
根据优先级进行:
- 最高:
两个相邻的数字相加结果为2位,结果大于原来的两个相邻的数。遍历顺序为从前往后。
但是,此种情况不存在,最大也就9 + 9 =18,18也还是小于99 - 中等:
相邻两个数相加结果位数为2位,但是结果比原来小。遍历顺序为从后往前。因为要是前面的话一变小,高位会首先变小,数字肯定变得更小,要是从低位开始遍历,虽然变小,但是变化的是低位的数字,不至于变得更小。 - 最低:
两个相邻数字相加结果为1位,结果肯定还是变小。遍历顺序为从前往后。相加虽然变成一位,但是该位的数字变得更大了,在高位相对不会变得更小。
该种情况可以简化:对第一个数字和第二个数字做加和运算即可
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 1e5+5;
void solve()
{
string s;
cin>>s;
//中等
for(int i=s.size()-2;i>=0;i--)
{
int x = s[i]-'0' + s[i+1]-'0';
int cur = (s[i]-'0')*10 + s[i+1]-'0';
if(x <= cur && x>=10)
{
string t = to_string(x);
s[i] = t[0];
s[i+1] = t[1];
for(auto a:s) cout<<a;
cout<<endl;
return ;
}
}
//最低
int x = s[0]-'0' + s[1]-'0';
cout<<x;
for(int i=2;i<s.size();i++) cout<<s[i];
cout<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}
C. Monsters And Spells
n个怪兽,第i个怪兽在秒出现,血量为.当前力量有两种变化方式:
1.在原来攻击力的基础上加一
2.攻击力变为1消耗值为每次的攻击力的和,求打完所有怪兽的最小消耗值
以由简到复杂的思路进行分析:
-
只有一个怪兽。它在秒出现,血量为,那么在秒时,攻击力要为
1,即攻击力递增区间为,总消耗值为 -
有两个怪兽。
-
如果两个怪兽出现互不干扰(就是后面出现的怪兽需要变为1的时间点在第一个怪兽出现时间点的后面),还是上面的计算方法,两个分别计算即可。
-
两个怪兽(设为
i和j,)干扰了。 两个区间本来为,出现干扰交叉也就是了。本来这里应该变成1的(这个位置如果是1的话见下),但是这又在i的地方,这时攻击力必须为才能灭掉怪兽,所以后面必须递增下去,即区间是递增的,初值不再是1,而是接着前面的进行递增变化。
-
漏了一点,当时,这个位置还可以是1
可以发现:两个递增区间有交集,那么结果就是两个区间的并集,然后求总和。区间长度为len,结果就为
- 三个怪兽。
不干扰还是各算各的。干扰的话就是求区间的并集,区间长度也可以求出,也可以算出结果。
- 总结下来:就是所有怪兽的攻击力递增区间求并集,对于每个合并后的大区间,攻击力是从1开始递增的。
那么这样就很好解决了,求出所有的区间,区间合并,求一下交集,同时记录结果即可。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 1e5+5;
void solve()
{
int n;
cin>>n;
vector<pair<int,int>>p(n);
vector<int>k(n),h(n);
for(auto &i : k) cin>>i;
for(auto &i : h) cin>>i;
for(int i=0;i<n;i++)
p[i] = {k[i]-h[i]+1,k[i]};
sort(p.begin(),p.end());
ll res = 0 ;
ll l = 0,r = 0;
for(int i=0;i<n;i++)
{
if(p[i].first > r)
{
if(l && r) res += (r-l+1)*(r-l+2)/2;
l = p[i].first;
r = p[i].second;
}
else r = max((ll)p[i].second,r);
}
res += (r-l+1)*(r-l+2)/2;
cout<<res<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}
D. Martial Arts Tournament
一系列数,确定两个边界
x和y,使w<x的数有2的幂次个,使的数有2的幂次个,使的数有2的幂次个,你可以添加任意数,求要满足上述条件需要添加的最少的个数
因为,所以我们记录数字出现的个数可以使用桶操作。
需要记录一下数字出现个数的前缀和和后缀和
pre[i]:代表数字出现次数的和为i次时,实际数字出现次数的前缀和
nxt[i]:代表数字出现次数的和为i次时,实际数字出现次数的后缀和
我们枚举左部分和右部分数字出现的次数,次数分别为i和j,次数以2次幂增长。
左部分需要添加的个数:
右部分需要添加的个数:
中间部分实际剩余数的个数:
中间部分数的个数mid我们需要给他弄到满足
中间部分需要添加的个数:
总的需要添加的个数:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
void solve()
{
int n;
cin>>n;
vector<int>a(n+1),pre(n+1),nxt(n+1);
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
a[x] ++;
}
int sum = 0;
for(int i=1;i<=n;i++)
{
for(int j=sum;j<sum+a[i];j++) pre[j] = sum;
sum += a[i];
}
sum = 0;
for(int i=n;i>=1;i--)
{
for(int j=sum;j<sum+a[i];j++) nxt[j] = sum;
sum += a[i];
}
int res = 1e9;
for(int i=1;i<=n;i<<=1)
for(int j=1;j<=n;j<<=1)
{
int mid = 1;
while(mid < n-pre[i]-nxt[j]) mid <<= 1;
res = min(res,mid-n+i+j);
}
cout<<res<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}