这题先分为两种情况,k是奇数还是偶数,注释很详细啦。
偶数的情况下,从左到右有0就直接把0变成1,具体操作是先这个0和后面一个0的位置配套互相翻一次,其他的位置不变,使用k--就可以了,当然,后面可能没有0了,那就全部翻最后一位即可。
奇数的话就先翻一次,k就变成偶数了,调用上面的弄偶数的函数即可。那这一次该怎么翻呢,如果第一位是1,直接按着他不变翻一次(k--);否则找到第一个出现的1,翻一次(k--),前面的0就都是1了,如果找不到1(即全是0)的话就简单了,逮住最后一位一直翻,因为是奇数次,就变成1111...110了
//#include<stdio.h>
#include<cstring>
#include<iostream>
//#include<algorithm>
using namespace std;
typedef long long ll;
ll b[200005],c[200005];//b数组用来存0的位置,c是每个位置翻转的次数
ll t,n,k,ti,i,j;
string a;
void odd()
{
t=0;
for(i=0; i<n; i++)
{
if(a[i]=='0')
{
b[t++]=i;//0出现的位置
}
}
for(i=0; i<t&&k; i++,k--)
{
a[b[i]]='1';
c[b[i]]=1;//该位置翻转一次,后面的先不用管,
//因为如果还有0的话就与他配合翻转,没有的话就和n-1位配合翻转
}
if(k)//全部是1了,还剩下的k就全部用于n-1位置
{
if(k&1)//之前出现的0次数是奇数时,说明有一个0没位置配套,那给n-1位就可以了,n-1位跟着翻奇数次,
//此时n-1翻了奇数次,取反,之后(偶数-两奇数和)还是偶数
{
if(a[n-1]=='0')a[n-1]='1';
else a[n-1]='0';
c[n-1]+=k;
}
else//前面的0刚好全部配套
{
c[n-1]+=k;
}
}
cout<<a<<endl;
for(i=0; i<n; i++)
{
printf("%lld ",c[i]);
}
cout<<endl;
}
void eve()
{
if(a[0]=='1')//第一位是1,那他不能变,翻转一次,k就是偶数了
{
k--;
c[0]=1;
for(i=1; i<n; i++)
{
if(a[i]=='1')a[i]='0';
else a[i]='1';
}
}
else//第一位是0,找到第一个出现的1,翻一次,前面的就都是1了,且k为偶数了
{
int f=0;
for(i=1; i<n; i++)
{
if(a[i]=='1')
{
f=1;
break;
}
}
if(!f)//全是0,k又是奇数,逮住最后一位一直翻,就是111....10
{
for(i=0; i<n-1; i++)
{
printf("1");
}
printf("0\n");
for(i=0; i<n-1; i++)
{
printf("0 ");
}
printf("%lld\n",k);
return;
}
k--;//找到了第一个1,他不变,其他的翻转
c[i]=1;
for(j=0; j<n; j++)
{
if(j!=i)
{
if(a[j]=='1')a[j]='0';
else a[j]='1';
}
}
}
odd();//k变成偶数了
}
int main()
{
cin>>ti;
while(ti--)
{
cin>>n>>k;
cin>>a;
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
if(k%2==0)
{
odd();
}
else
{
eve();
}
}
}