A. Red Versus Blue
样例输入:
6
3 2 1
10 6 4
11 6 5
10 9 1
10 8 2
11 9 2
样例输出:
RBR
RRBRBRBRBR
RBRBRBRBRBR
RRRRRBRRRR
RRRBRRRBRR
RRRBRRRBRRR
题意:两个队伍进行比赛,一共n场比赛,其中红队赢a场,蓝队赢b场,让我们输出一种比赛结果方案,使得任意一方连胜次数最大值最小。
分析:这个我们直接贪心求解即可,就是我们统计一下平均一方赢多少次另一方可以赢一次,一开始我们是用上取整,当一方获胜次数可以被另一方整除的时候我们直接循环输出即可。然后我们直接按照这个方法进行模拟求解即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int main()
{
int T;
cin>>T;
while(T--)
{
int n,a,b;
scanf("%d%d%d",&n,&a,&b);
int cnt=a/(b+1);
int t=a%(b+1);
for(int i=1;i<t;i++)
{
for(int j=1;j<=cnt+1;j++)
printf("R"),a--;
printf("B"),b--;
}
while(b--)
{
for(int j=1;j<=cnt;j++)
printf("R"),a--;
printf("B");
}
for(int j=1;j<=a;j++)
printf("R");
puts("");
}
return 0;
}
B. Bit Flipping
样例输入:
6
6 3
100001
6 4
100011
6 0
000000
6 1
111001
6 11
101100
6 12
001110
样例输出:
111110
1 0 0 2 0 0
111110
0 1 1 1 0 1
000000
0 0 0 0 0 0
100110
1 0 0 0 0 0
111111
1 2 1 3 0 4
111110
1 1 4 2 0 4
题意:给定一个长度为n的01串,然后我们可以对这个字符串进行k次操作,每次操作选定一个字符,操作后除了这个字符以外的其他字符全部反转,求k次操作后字符串的最大字典序,还需要输出每个字符的操作次数。
分析:我们先考虑第i个字符,如果第i个字符是1,这个时候需要看一下k的奇偶性,如果k是奇数,那么我们需要操作第i个字符一次,那么这一次操作,第i个字符不会发生变化,然后剩下的操作次数为偶数,剩余的操作只要是不操作第i个字符,那么最后第i个字符一定是1.同理贪心可以得到其他的情况,如果k是偶数,那么对于第i个字符是1的情况我们就可以直接不操作这个字符,对于第i个字符是0的情况我们就可以操作这个字符一次。贪心来想我们就需要从第一个位置开始往后考虑,尽量使得每一个位置都为1,最后如果剩余操作次数就全部操作最后一个字符。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
char s[N];
int t[N];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) t[i]=0;
scanf("%s",s+1);
int cnt=0;
for(int i=1;i<=n;i++)
{
if(k==cnt) break;
if(s[i]=='1')
{
if(k&1)
{
t[i]++;
cnt++;
}
}
else
{
if(k%2==0)
{
t[i]++;
cnt++;
}
}
s[i]='1';
if(cnt==k)
{
if(k&1)
for(int j=i+1;j<=n;j++)
{
if(s[j]=='0') s[j]='1';
else s[j]='0';
}
break;
}
}
if(k!=cnt)
{
for(int i=cnt+1;i<=k;i++)
t[n]++;
if((k-cnt)&1) s[n]='0';
}
for(int i=1;i<=n;i++)
printf("%c",s[i]);
puts("");
for(int i=1;i<=n;i++)
printf("%d ",t[i]);
puts("");
}
return 0;
}
C. Line Empire
样例输入:
4
5 2 7
3 5 12 13 21
5 6 3
1 5 6 21 30
2 9 3
10 15
11 27182 31415
16 18 33 98 874 989 4848 20458 34365 38117 72030
样例输出:
173
171
75
3298918744
题意:给定n个城市的位置(位置均大于0),一开始有一个首都位于0号点,然后我们每次可以花费a⋅|c1−c2|的代价进行迁都,其中c1是当前首都位置,c2是要迁都到的位置,a是一个迁都代价系数,前提是c2这个城市已经被占领了。我们还可以花费b⋅|c1−c2|占领位于c2位置的城市,但是不改变首都的位置,而且c1和c2之间不能有未被占领的城市,其中c1是首都的位置。问我们占领所有的城市所需要的最小代价(最后首都的位置无所谓)
分析:首先我们可以知道我们将首都从0号点直接迁至k号点花费的代价和从0号点经过若干次迁都到达k号点所花费的代价是相同的(前提是每次迁都的方向都是沿着x轴正方向),那么我们可以发现为了使得占领城市的代价尽量小,我们就要使得首都的位置尽量靠近我们要占领的城市。假如最优结果中首都的位置是k号点,那么在占领前k个城市中每占领一个城市我们就将首都迁至这个位置,这样一定是最优的,这也是很容易理解的,因为我们保证了每次占领城市所需要的代价都是最小的,而迁都的代价又是固定的,剩余的未被占领的城市直接都相对于k号点进行占领即可。所以我们的目的就是枚举最后的首都的位置然后直接对于每个位置O(1)求代价即可,我们需要预处理一些信息。
详情见代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
long long p[N];
long long s[N];
int main()
{
int T;
cin>>T;
while(T--)
{
long long n,a,b;
scanf("%lld%lld%lld",&n,&a,&b);
for(int i=1;i<=n;i++)
{
scanf("%lld",&p[i]);
s[i]=s[i-1]+p[i];
}
long long ans=s[n]*b;
for(int i=1;i<n;i++)
ans=min(ans,p[i]*a+p[i+1]*b+(s[n]-s[i+1]-(n-i-1)*p[i])*b);
printf("%lld\n",ans);
}
return 0;
}
D. Reverse Sort Sum
样例输入:
5
4
2 4 2 4
7
0 3 4 2 3 2 7
3
0 0 0
4
0 0 0 4
3
1 2 3
样例输出:
1 1 0 1
0 1 1 0 0 0 1
0 0 0
0 0 0 1
1 0 1
题意:定义f(k,A)是将A数组前k个元素按照非递降顺序排序后的数组。其中A数组是一个由01字符组成的数组。现在已知B数组,其中B=,求解A数组。
分析:这个我们可以倒着进行考虑,先考虑第n个数,如果第n个数是等于n的,那么说明第n个位置A数组元素的值是1,如果B数组中第n个位置的值是等于0的,说明A数组中所有元素都等于0,如果B[n]=1,说明A[n]=1.第n次排序后的数组一定是0000……111这种形式,而且数组中1的个数我们是能够直接求出来的,所以我们就可以知道前n-1次排序的结果,也就是用b[1~n]-0000……111,其中1的初始位置我们是可以通过1的个数推出来的,但是这个地方不能暴力减,我们需要用数组数组维护差分进行优化。能够发现第n个位置的值并不会影响前n-1次排序的结果,所以这个时候第n个位置的影响我们就已经分析完了,这个时候我们就需要来分析一下前n-1个数的情况了,这是相同的问题,所以我们只需要按照上面方法倒着分析每一位的情况即可。
细节见代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int a[N],b[N],c[N];
int n;
int lowbit(int x)
{
return x&-x;
}
void add(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=val;
}
int sum(int x)
{
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=c[i];
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d",&n);
long long s=0;
for(int i=1;i<=n;i++)
scanf("%d",&b[i]),s+=b[i],a[i]=c[i]=0;
for(int i=1;i<=n;i++)
add(i,b[i]-b[i-1]);
long long cnt=s/n;
for(int i=n;i>=1;i--)
{
b[i]=sum(i);
if(b[i]==i)
{
a[i]=1;
add(i-cnt+1,-1);
add(i+1,1);
cnt--;
}
else if(b[i]==1)
{
add(i-cnt+1,-1);
add(i+1,1);
}
else
break;
}
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
puts("");
}
return 0;
}