CodeForces 1382 - C.Prefix Flip (Easy Version + Hard Version) - 思维 + 构造

题目传送门:

C1. Prefix Flip (Easy Version)

C2. Prefix Flip (Hard Version)

题目描述

给两个长度为n的01串a,b,选择操作 i 即将串的前i个元素取反并翻转(比如1100取反并翻转前3个数变为1000,用操作3表示),对a串进行若干操作使其与b串相同,输出操作数和具体操作。

Easy Version:总的n不超过1e3,操作数不超过3n

Hard Version:总的n不超过1e5,操作数不超过2n

思路

题目说可以证明a一定能变成b,那么表示我们一定可以构造一种通用操作方式使得a变成b,并且题目暗示了通解操作数的数量级为3n和2n。

Easy Version:

我们希望a与b在第i个元素不同时修改第i个元素并且不影响其他元素,但是我们知道操作是对前缀进行取反和翻转,通过观察我们容易发现执行操作i后第i个元素跑到第1个位置,于是就可以想到一种构造方法:

  • 遇到a与b的第i个元素不同
  • 执行操作i(取反并翻转前i个元素)
  • 执行操作1(取反并翻转第1个元素)
  • 执行操作i(取反并翻转前i个元素)

可以发现第i个元素取反了3次,前i - 1个元素取反了2次,并且前i个元素均翻转了两次,相比操作前,之后第i个元素发生了变化,并且很容易看出操作数不超过3n,因为每个元素不同,至多执行3次操作。

Hard Version:

 很显然对于操作数不超过2n,我们需要一种新的构造

如果只是单纯的取反,我们只需从后往前操作即可避免前缀的影响,然而翻转我们是很难避免的,但是对于全0和全1的序列这两种特殊序列,翻转是无影响的。那么我们只需要用操作构造全0或全1的序列即可,构造方式如下:

  • 构造全0或全1的序列,对于第i个元素,如果与第i - 1个元素不同(前i - 1个元素是相同的),执行操作i - 1,执行过后前i个元素都与第i个元素相同
  • 从后往前,如果b第i个元素与b的第i + 1个元素不同(此时a的前i + 1个元素与b的第i + 1个元素相同),对a执行操作i(因为我们没有真的去操作,只是记录操作)

可以发现第一步至多执行n - 1次,第二步至多执行n - 1次,总操作数不超过2n。

 代码

Easy Version:

#include 
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;
typedef pair pll;
const int mod = 1e9 + 7;
const int N = 1e3 + 10;
const int INF = 0x3f3f3f3f;
ll qpow(ll base, ll n){ll ans = 1; while (n){if (n & 1) ans = ans * base % mod; base = base * base % mod; n >>= 1;} return ans;}
ll gcd(ll a, ll b){return b ? gcd(b, a % b) : a;}
char a[N], b[N];
int main()
{
	int t;
	cin >> t;
	while (t --){
		int n;
		scanf("%d", &n);
		scanf("%s", a + 1);
		scanf("%s", b + 1);
		vector ans;
		for (int i = 1; i <= n; ++ i){
			if (a[i] != b[i]) {
				ans.pb(i);
				if (i > 1) {
					ans.pb(1);
					ans.pb(i);
				}
			}
		}
		int num = ans.size();
		printf("%d ", num);
		for (int i = 0; i < num; ++ i) printf("%d ", ans[i]);
		puts("");
	}
	return 0;
}

Hard Version:

#include 
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;
typedef pair pll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
ll qpow(ll base, ll n){ll ans = 1; while (n){if (n & 1) ans = ans * base % mod; base = base * base % mod; n >>= 1;} return ans;}
ll gcd(ll a, ll b){return b ? gcd(b, a % b) : a;}
char a[N],b[N];
int ans[N << 1], n, tot;
int main(){
	int t;
	cin >> t;
	while (t --){
		tot = 0;
		scanf("%d", &n);
		scanf("%s", a + 1);
		scanf("%s", b + 1);
		a[0] = a[1], b[n + 1] = a[n];//这样就不用特判n == 1
		for (int i = 1; i <= n; ++ i){
			if (a[i] != a[i - 1]) ans[++ tot] = i - 1;
		}
		for (int i = n; i >= 1; -- i) {
			if (b[i] != b[i + 1]) ans[++ tot] = i;
		}
		printf("%d ", tot);
		for (int i = 1; i <= tot; ++ i)  printf("%d ", ans[i]);
		puts("");
	}
	return 0;
}

 

你可能感兴趣的:(构造,CodeForces)