Codeforces Round 825 A-C1 D


Codeforces Round #825 (Div. 2) A-C1 D

A. Make A Equal to B

题目大意: 给定两个$01$序列$a$,$b$长度为$n(1\leq n\leq 1e2)$,现在有两种操作,第一种操作是选择一个位置进行反转,第二个操作是任意排序$a$序列,问最少需要几次操作能让序列$a$等于序列$b$

解题思路: 首先我们先思考一下,我们刚开始一定要让序列$a$和$b$中的$01$个数相同,然后在这个前提下,如果两个序列在增加$1$的过程中相同了,就不进行二操作,否则就进行二操作。如何判断两个序列是否在过程中就相同了呢?我们可以考虑将序列中的$0$变成$1$,然后看哪个序列中原本的$1$多,如果$b$中多就变$a$,$a$中多实际上就是变$b$

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		int na,nb;
		na = nb = 0;
		cin >> n;
		for(int i = 1;i <= n;++i)
		{
			cin >> a[i];
			if(a[i]) na++;
		}
		for(int i = 1;i <= n;++i)
		{
			cin >> b[i];
			if(b[i]) nb++;
		}
		int f = 1;
		int ck = 0;
		if(na > nb) ck = 1;
		if(na < nb)
		{
			for(int i = 1;i <= n;++i)
			{
				if(!a[i]) continue;
				if(a[i] != b[i]) f = 0;
			}
		}
		else
		{
			for(int i = 1;i <= n;++i)
			{
				if(!b[i]) continue;
				if(a[i] != b[i]) f = 0;
			}
		}
		cout << abs(na - nb) + (1 - f) << "\n";
	}
}

B. Playing with GCD

题目大意: 给定一个长度为$n(1\leq n \leq 2e5)$的序列,问是否存在一个长度为$n + 1$的序列$b$,满足$a_i = gcd(b_i,b_{i + 1})$

解题思路: 观察样例可得我们可以对原序列中的$a_{i - 1}$,$a_i$和$a_{i + 1}$进行分析,这三个数字分别由$b_{i - 1}$,$b_i$,$b_{i + 1}$,$b_{i + 2}$

考虑$b_i$和$b_{i + 1}$实际上还在$a_{i - 1}$和$a_{i + 1}$中,我们考虑$gcd$的性质实际上是去求若干个数字的质因子取$min$

那么我们可以对$a_{i- 1}$和$a_{i + 1}$取$gcd$,如果$a_i$不能和他们的$gcd$取余获得$0$的话,那么实际上就是不可以的,说明还有其他的质因子存在

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		for(int i = 1;i <= n;++i) cin >> a[i];
		int f = 1;
		for(int i = 2;i <= n - 1;++i)
		{
			int gd = __gcd(a[i - 1],a[i + 1]);
			if(a[i] % gd) f = 0;
		}
		if(f) cout << "YES\n";
		else cout << "NO\n";
	}
}

C1. Good Subarrays (Easy Version)

题目大意: 给定一个长度为$n(1\leq n \leq 2e5)$的序列,找出这个序列中有多少个序列满足好序列,好序列的要求是对于一段序列第$i$个元素大于等于$i$

解题思路: 固定左端点取计算右端点在哪里。我们可以发现这样一件事情,如果我在当前这个位置$i$右端点到达$j$,那么我到$i + 1$的话,我可以继续从$j$往右边移动,满足双指针的性质,直接写就可以。

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		for(int i = 1;i <= n;++i) cin >> a[i];
		int ans = 0;
		int j = 1;
		int now = 1;
		for(int i = 1;i <= n;++i)
		{
			if(j < i)
			{
				j = i;
				now = 1;
			}
			while(a[j] >= now && j <= n)
			{
				// cout << "i -> "<< i << " " << j << " " << now<< "\n";
				j++;
				now++;
			}
			j--,now--;
			int num = j - i + 1;
			ans += num;
			now--;
			// cout << i << " " << j << "\n";
		}
		cout << ans << "\n";
	}
}

D. Equal Binary Subsequences

题目大意: 给定一个长度为$2n(1\leq n \leq 1e5)$的$01$串,可以进行以下的操作一次,选择一个子序列,并且把这个子序列中的数字往前移动一个,如果是第一个就移动到最后一个,问是否能够将这个$01$串分割成两个子序列,使得这两个子序列相同

解题思路: 首先我们先考虑无法构成的情况,如果$0$的个数或者$1$的个数是奇数,那么这个序列肯定就无法构成

做一个大胆的猜想,假设目前剩下的情况下所有情况都是有解的,那么剩下的串可能是由若干个$00$ $01$ $10$ $11$组成的

我们从前往后对于一个子序列来说$00$和$11$肯定是可以直接放进去的,那么对于$01$和$10$呢?

我们可以考虑把他们放到操作里面去变换,那么实际上我们只需要把奇数位置上面的$1$放到偶数位置上去,把偶数位置上面的$1$放到奇数位置上去

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		cin >> str;
		str = " " + str;
		int num = 0;
		n <<= 1;
		for(int i = 1;i <= n;++i)
		{
			num += (str[i] == '1');
		}
		if(num & 1)
		{
			cout << -1 << "\n";
			continue;
		}
		vector<int> pos;
		for(int i = 1;i <= n;i += 2)
		{
			if(str[i] == str[i + 1]) continue;
			pos.push_back(i);
		}
		vector<int> ans;
		for(int i = 0;i < pos.size();++i)
		{
			int now = pos[i];
			if((i & 1) == str[now] - '0')
			{
				ans.push_back(now);
			}
			else ans.push_back(now + 1);
		}
		cout << ans.size() << "\n";
		for(auto to:ans)
		{
			cout << to << " ";
		}
		cout << "\n";
		for(int i = 1;i <= n;i += 2) cout << i << " \n"[i == n - 1];
	}
}

文章作者: Treasure
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Treasure !
  目录