A.Short Substrings
题意:有一个字符串,从左至右列出所有长度为2的子串,然后连起来,这就是题目给的串。要我们输出原来的串。输出开头,中间隔位输出,再输出结尾。
void solve()
{
string s;
cin >> s;
cout << s[0];
for (int i = 1; i < s.size() - 1; i += 2)cout << s[i];
cout << s[s.size() - 1] << endl;
}
B.Even Array
给你n个数,下标从0开始,可以通过交换某两个数使得每位数字和他的下标奇偶性相同,求最小交换次数,不可能的情况输出-1。我们只让不符合要求的奇数数字和偶数数字交换,所以记录这两种数字的数量,只有奇数数字个数==偶数数字个数,才能交换完,因为奇数数字和奇数数字交换是没有意义的。最后的交换次数就是奇数或者偶数的数量。
int n;
int a[55];
void solve()
{
int odd = 0, ev = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
if (a[i] % 2 == 1 && i % 2 == 0)odd++;
else if (a[i] % 2 == 0 && i % 2 == 1)ev++;
}
if (odd == ev)cout << odd << endl;
else cout << "-1\n";
}
C.Social Distance
题意:给一个长度为n的01串,保证每个1都相差至少 k k k个位置,即 [ i − k , i + k ] [i-k,i+k] [i−k,i+k]之间都没有其他的1。问01串内还有几个0在合法的前提下可以换成1。在这里 n n n和 k k k都是 2 e 5 2e5 2e5级别的,所以纯暴力是不行的。我们枚举串的每一位,如果他是0,判断能不能变成1,如果能,计入答案。如果是1,直接跳到 i + x + 1 i+x+1 i+x+1。
#define vint vector<int>
#define pb push_back
#define clr(a, b) memset((a), (b), sizeof(a))
int n, x;
void solve()
{
clr(vis, 0);
cin >> n >> x;
string s; cin >> s;
vint V;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '1')i += x;//直接跳过k个格子
else
{
bool f = 0;
int p = -1;//p记录右边最近的1
//我们是从左边枚举过来的,可以保证左边k位里是没有1的,否则一定会跳过现在这个点
for (int j = i + 1; j < s.size() && j <= i + x; j++)
{
if (s[j] == '1')//有1就break
{
p = j;
f = 1;
break;
}
}
//这里说明现在这个0可以换成1,这个点变成1后,理所当然往后跳k个格子
if (!f)
{
V.pb(i);
s[i] = '1';
i += x;
}
else i = p + x;//直接跳到右边第一个1的再右边x位
}
}
cout << V.size() << endl;
}
D.Task On The Board
题意:给你一个字母串
s
s
s,你需要构造一个长度为
m
m
m的字符串
t
t
t,
t
t
t应为
s
s
s在删掉任意位字母之后的任意一个排序。再给你一个含有
m
m
m个数字的
b
b
b数组,
b
i
b_i
bi是 在
t
t
t中,所有比
t
i
t_i
ti大的字母和
t
i
t_i
ti的相对位置的和。
我们以test4为例:
ecoosdcefr
10
38 13 24 14 11 5 3 24 17 0
我们首先可以看到,
b
[
10
]
=
0
b[10]=0
b[10]=0,说明这一位是字典序最大的一位,且仅有一位。接着我们假装他不存在,那么他给其他b[i]的贡献也没了,所以我们把其他的
b
i
b_i
bi都减去和
t
i
t_i
ti和
t
[
10
]
t[10]
t[10]的相对位置,但是要注意,这一个位置还是存在的,只是我们选择性忽视它给的贡献。那么
b
i
b_i
bi变为下面这个数组:
29 5 17 8 6 1 0 22 16 _
我们发现,又有新的0出现,这个位置就是字典序第二大的字母,同时我们保留上一轮的0的位置,继续重复上面的操作:
23 0 13 5 4 0 _ 21 14 _
这里是有两个0,所以剩下的每位置要删除两个贡献。
为了看的更清楚,做了张图。
我们就能凭借0出现的先后顺序,得到他们的字典序大小排序,再去
s
s
s里找足够数量的字母。那么这里的顺序(下标)就是:10->7->2,6->5>4,9->3>1,8。
#define vint vector<int>
#define pb push_back
#define clr(a, b) memset((a), (b), sizeof(a))
int n;
int a[55];
bool vis[55];
int num[55];
void solve()
{
clr(num, 0);
clr(vis, 0);
string s; cin >> s;
for (int i = 0; i < s.size(); i++)num[s[i] - 'a']++;
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
vint V, res[55];//V是这一轮新的0的下标,res是每一轮新出的0的下标,其实感觉可以合并成一个
int pos = 0, now = 0;//pos是记录当前的轮数,now是记录已经有几个0了,当有n个0时,就是while循环退出的时候
while (1)
{
V.clear();
for (int i = 1; i <= n; i++)
if (!vis[i] && a[i] == 0)
{
V.pb(i);
vis[i] = 1;
res[pos].pb(i);
now++;
}
pos++;
for (int i = 1; i <= n; i++)
if (a[i] > 0)
for (int p : V)a[i] -= abs(i - p);
if (now >= n)break;
}
string ans;
ans.resize(n);
int j = 0;//j是当前选到的字母的位置,不会重置为0,因为我们是从最小的字母开始找,到后面要保证所选的字母的字典序要越来越大
//下面找数量够的字母
for (int i = pos - 1; i >= 0; i--)
{
int sz = res[i].size();//表示现在我们要找的字母的数量一定要大于等于sz
for (j; j < 26; j++)
{
if (num[j] >= sz)
{
for (int p : res[i])ans[p] = (char)('a' + j);
j++;//因为这里break了,不会执行j++,这里要我们再写一遍
break;
}
}
}
for (int i = 1; i <= n; i++)cout << ans[i];
cout << endl;
}
E.Necklace Assembly
明天看看