A. Red Versus Blue
题意:给出r,b和为n,且r严格大于l。求输出r个R和b个B的字付出,使得最大连续R的个数最小
一共有b个B,那么就有b+1个空位,先平均分配再把额外的R在有些位置加一个
#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--){
int n,r,l;
cin>>n>>r>>l;
int num=num=r/(l+1);
for(int i=1;i<=l+1;i++){
for(int j=1;j<=num;j++)cout<<"R";
if(i<=r%(l+1))cout<<"R";
if(i==l+1)continue;
cout<<"B";
}
cout<<endl;
}
AC
}
B. Bit Flipping
题意:给定一个长度为n的01串,和k次操作,一次操作可以选择一位保留其余位置全部取反
求可得到的最大串
对于01串来说肯定是去贪心考虑,要最大肯定要满足无论付出什么代价都要使前面位为1
然后分k奇偶去讨论就行,其次对于这个操作0次和2次效果是一样的
#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
const int MAXN=2e5+7;
char s[MAXN];
int t,n,k,vis[MAXN];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--){
cin>>n>>k;
cin>>s;
int cnt=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<n-1;i++){
if(k&1){
if(s[i]=='1'){
if(cnt<k){vis[i]=1;
cnt++;}
else s[i]='0';
}
else s[i]='1';//对于k为奇数如果不对该位做操作那么一定取反
}
else{
if(s[i]=='0'&&cnt<k){
vis[i]=1;
cnt++;
s[i]='1';
}
}
}
if(cnt%2){
if(s[n-1]=='1')s[n-1]='0';
else s[n-1]='1';
}
cout<<s<<endl;
for(int i=0;i<n-1;i++){
if(vis[i])cout<<"1 ";
else cout<<"0 ";
}
cout<<k-cnt<<endl;
}
AC
}
C. Line Empire
题意:你需要依次占领n个王国,初始点在0,给出a,b。占领一个王国消耗b*他们之间的距离,在占领后可以选择搬迁过去,问最小消耗总和。
对于一个点如果搬迁过去的消耗加占领后面的点的消耗小于原来的,那我们一定要搬迁过去。
我们贪心的去考虑,如果有两个点c1,c2都能搬,那我们一定是先搬到c1,再到c2一定是最优解。相比于直接搬到c2,他们的搬迁费用是一样的,但在c1,c2之间的这些点的占领费用从c1出发会更小。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+7;
#define AC return 0;
#define int long long
int t,n,a,b,c[MAXN],sum;
int check(int i,int st){
int val1=a*(c[i]-st)+b*(sum-(n-i)*c[i]);//搬过去的费用
int val2=b*(sum-(n-i)*st);//不搬的费用
return val1<=val2;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--){
cin>>n>>a>>b;
sum=0;
for(int i=1;i<=n;i++){
cin>>c[i];
sum+=c[i];
}
int st=0,ans=0;
for(int i=1;i<=n;i++){
ans+=b*(c[i]-st);
sum-=c[i];
if(check(i,st)){
ans+=a*(c[i]-st);//搬过去更优
st=c[i];
}
}
cout<<ans<<endl;
}
AC
}
D. Reverse Sort Sum
题意:有一个长度为n的0,1数组,定义bi为a前i个数从小打大排序剩下不变,令数组c为b1-bn的各位置总和,现给出c求出a
对于每个ci,他的组成是由i-1个该位本来的数和若干个1和0,而假设在排序到某x位置之后该位变为0,那么bx后面的情况该位一定位0。假设我们已经知道了该位的数字bit,那么-(i-1)*bit
后就是有多少个1,由于排序范围的扩大该位一定是从1变为0的,那么我们就可以知道在哪个位置变为0,那么该位置对应原来的值为0.
#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
const int MAXN=2e5+7;
int t,n,a[MAXN],ans[MAXN],vis[MAXN];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--){
cin>>n;
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)cin>>a[i];
int st=1;
while(a[st]==0){
ans[st]=1;//标记为1,实际代表0
st++;//找到第一个不为0的点,前面的点全部是0不影响后面
}
for(int i=st;i<=n;i++){
a[i]-=(i-1)*(1-ans[i]);
ans[a[i]+i]=1;//标记第i个0
//cout<<a[i]+i<<endl;
}
for(int i=1;i<=n;i++){
if(ans[i]==1)cout<<"0 ";
else cout<<"1 ";
}
cout<<endl;
}
AC
}
对于第i位,我们都能找出第i个0所在的位置,剩下的未被标记的点就是1啦。然后0没有那么多的话剩下的点会跳到n以外不需要去考虑。
为了便于理解模拟一组样例吧,对于 2,4,2,4来说显然第一位为1,减去(i-1)后还是2,那么就有2个bi(该位已被排序的bi)在该位是1,那么一定是b1,b2,由此可以确定b3在该位置为0。那么第二位未被标记一定是1,这样对于每一位来说它最少确定后面一位的情况所以可以一直递推下去,第二位4在减去(i-1)后为3,那么第五位为0,超出范围了无需考虑也证明了在该位后无0存在。
EF有缘再补吧!
abc还是写的太慢了orz
等到1点半交的d一发过了,果然赛后正确率直线提升,就是血压有点高了