【周赛1】F G H (难度DIV2 C D)

F

题目来源

Problem - 1559C - Codeforces

简述:

  • 一共有n+1个村庄,2n-1条小路
  • 其中有n-1条小路是顺序连接着村庄1-2-3-4-5……n
  • (第 n+1个村庄被孤立)
  • 再有n条小路,通过数组ai存储0和1描述它们的连接方式
  • 0:代表小路从村庄i指向村庄n+1
  • 1:代表小路从村庄n+1指向村庄i
  • 问可以单向连接所有村庄的方式(输出一种)

解析

  • 简图如下

  •  考虑以下三种情况
  1. a[1]==1 (n+1)~(1)~(2)~ ...~ (n)
  2. a[n]==0   (1)~(2)~ ...~(n)~(n+1)
  3. a[k]==0&&a[k+1]==1  (1)~(2)~...~(k)~(n+1)~(k+1)~...~(n)

只要满足上述三个情况之一则可以输出一条路径

否则输出-1

代码段

void solve()
{
	int n;
	cin >> n;
	vector<int>a(n + 1);
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	if (a[1] == 1)
	{
		cout << n + 1 << ' ';
		for (int i = 1; i <= n;i++)
			cout << i << ' ';
		return;
	}
	else if (a[n] == 0)
	{
		for (int i = 1; i <= n + 1; i++)
			cout << i << ' ';
		return;
	}
	for (int i = 1; i < n; i++)
	{
		if (a[i] == 0 && a[i + 1] == 1)
		{
			for (int j = 1; j <= i; j++)
				cout << j << ' ';
			cout << n + 1 << ' ';
			for (int j = i + 1; j <= n; j++)
				cout << j<< ' ';
			return;
		}
	}		
	cout << -1 << endl;
}

G

题目来源

Problem - 1553C - Codeforces

简述

  • 总共有1-10  10个球,奇数球a队踢,偶数球b队踢
  • 如果是 1 ,则进球
  • 如果是0 则不进球
  • 如果是? 未知
  • 问最少踢多少球就可以不用比下去了
  • 某队得分>另一只队的得分+剩下的点球数

解析

  • 既然要求最少的场数,我们不妨将某一队的不确定的场数看作是全进球
  • 首先假设b队(偶数球)问号场全进,比较当b>a-(10-i)/2(假设剩余的场数全进)
  • 更新最小情形
  • 再假设a队(奇数球)问号场全进,比较当a>b-(10-i+1)/2(假设剩余的场数全进)
  • 更新最小情形

代码段 

void solve()
{
	string s;
	cin >> s;
	int a = 0, b = 0,ans=10;
	int size = s.size();
	for (int i = 0; i < size; i++)
	{
		if ((i+1)& 1)
		{
			if (s[i] == '1')a++;
		}
		else
		{
			if (s[i] == '1' || s[i] == '?')
				b++;
		}
		if (b > a + (10 - i-1) / 2)
		{
			ans = min(ans,i+1);
		
		}
	}
	a = 0, b = 0;
	for (int i = 0; i < size; i++)
	{
		if (1 & (i+1))
		{
			if (s[i] == '1'||s[i] == '?')a++;
		}
		else
		{
			if (s[i] == '1')
				b++;
		}
		if (a > b + (10 - i ) / 2)
		{
			ans = min(ans,i+1);
			
		}
	}
	cout << ans << endl;
}

题目来源

Problem - 1553D - Codeforces

简述 

  • 给出两个字符串s1,s2
  • 要求对s1进行操作之后得到s2
  • 操作内容:
  • 如果对第一个字符操作,即删去第一个字符
  • 其他字符操作,删去此字符与前面一个字符,一次清除两个

解析

  • 首先我们将两个字符串倒置(相当于逆向遍历)
  • 然后使用双指针
  • i指向a,pos指向b
  • 在i向后遍历并寻找a[i]==b[pos]的同时清除不匹配的情况
  • 注意一次清除两个字符
  • 直到在a[i]中找到全部的b中的字符则可以输出
  • 这么操作的合理性在于
  • 首先如果我们遇到在b中不存在的字符,是一定要删去并且删两个,毫无疑问
  • 对于当前b[pos]我们在a中寻找到的第一个满足的字符a[i],我们就将它保留下来
  • 合理性在于
  • 对于下一个我们要在a中寻找的字符a[j],它与a[i]之间即使存在一个a[k]==b[pos],我们选择保留a[i]和a[k]是一样的
  • 举例:字符串1:ckckb 字符串2:cb
  • 保留第一个c后面b就会被删除,保留第二个c(第一个被删除),后面b依旧会被删除
  • 举例:字符串1:ckckcb 字符串2:cb
  • 保留第一个c,能够组成cb。保留第二个c(删除第一个),依旧能组成cb
  • 所以保留哪个符合的字符都可以,不妨就直接保存最先遇到的

代码段

void solve()
{
	string a, b;
	cin >> a >> b;
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	int pos = 0;
	for (int i = 0; i < a.size(); i++)
	{
		if (a[i] == b[pos])pos++;
		else i++;
		if (pos == b.size())break;
	}
	puts(pos == b.size() ? "YES" : "NO");
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nathan Qian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值