构造+思维:C - Prefix Flip (Easy Version)

题目链接:https://vjudge.net/contest/397850#problem/C
题意:将01字串a可以进行多少次操作变成b。
操作:将前缀i前面的数(包括i)是1的话变成0(是0的话变为1),然后再将其到前缀i之间的数反转。输出最少的操作数,并写出前缀i。
题解:因为需要反转,所以优先考虑后面的,又因为后面的b[i]是由a[0]变成的。所以需要判断是否需要先变a[0]。如果a[0]和b[i]相等的话,因为要由1变成0,所以需要先改变a[0]。然后再将其反转
代码:(复杂度(n*n))

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#define maxn 1200
using namespace std;
int a[maxn],b[maxn];
string aa,bb;
int sol[3*maxn];
int n;//串的长度 
void solve(int k)
{
	for(int i=0;i<=k;i++)
	    a[i]=1-a[i];
	for(int i=0;i<=k/2;i++)
	    swap(a[i],a[k-i]);
}
void duru()
{
	scanf("%d",&n);
	getchar();//getline也读空行,所以需要吸收 
	//01字串是连着的,所以需要用字符来处理 
	getline(cin,aa);
	for(int i=0;i<n;i++)
		a[i]=(int)(aa[i]-'0');
	getline(cin,bb);
	for(int i=0;i<n;i++)
		b[i]=bb[i]-'0';
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int num=0;//操作数 
		duru();
		for(int i=n-1;i>=0;i--)
		{
			if(a[i]==b[i])
			   continue;
			if(a[0]==b[i])
			{
				num++;
				sol[num]=1;//先变第一个 
			}
			num++;
			sol[num]=i+1;
			solve(i);
		}
		printf("%d ",num);
		for(int j=1;j<=num;j++)
		    printf("%d ",sol[j]);
		printf("\n");
	}
	return 0;
} 

hard版本n<=1e5,所以肯定会超时,所以简化修改交换值得那一步,然后用正序和逆序来代替。l,r表示最左侧和最右侧。

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#define maxn 120000
using namespace std;
int a[maxn],b[maxn];
string aa,bb;
int sol[3*maxn];
int n;//串的长度 
void duru()
{
	scanf("%d",&n);
	getchar();//getline也读空行,所以需要吸收 
	//01字串是连着的,所以需要用字符来处理 
	getline(cin,aa);
	for(int i=0;i<n;i++)
		a[i]=(int)(aa[i]-'0');
	getline(cin,bb);
	for(int i=0;i<n;i++)
		b[i]=bb[i]-'0';
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int num=0;//操作数 
		duru();
		int l=0,r=n-1;//最左侧,最右侧
		int xu=1;//1表示正序,-1表示逆序 
		for(int i=n-1;i>=0;i--)
		{
			if(xu==1)//正序 
			{
				if(a[r]==b[i])//最右边的和他比较,所以是r和他比 
				{
					r--;
					continue;
				}
			    if(a[l]==b[i])
			    {
				   num++;
				   sol[num]=1;//先变第一个 
			    }
			    num++;
			    l++;
			    sol[num]=i+1;
			    xu=-1;
			}
			else if(xu==-1)
			{
				if(a[l]!=b[i])//此时逆序l是最右边,所以l和他比
				{
				   l++; 
			       continue;
			    } 
			    if(a[r]!=b[i])
			    {
				   num++;
				   sol[num]=1;//先变第一个 
			    }
			    r--;
			    num++;
			    sol[num]=i+1;
			    xu=1;
			}
		}
		printf("%d ",num);
		for(int j=1;j<=num;j++)
		    printf("%d ",sol[j]);
		printf("\n");
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值