Codeforces Round #848 (Div. 2),C. Flexible String。cf #849 (Div. 4),G2. Teleporters (Hard Version)

Codeforces Round #848 (Div. 2),C. Flexible String

思路:

字符串a有cnt个不同字母(最多有10个不同字母,不是26个),而我们需要取num=min(k,cnt)种字母来取代,最大情况是C(5,10)=252种组合,所以我们完全可以dfs暴力所有组合。

#include <bits/stdc++.h>
using namespace std;
#define ll     long long
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
typedef pair<int, int> pii;

//double 型memset最大127,最小128
//std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 1e5 + 10;

int n, k, cnt, x[30], num;
ll ans;
bool vis[30];
string a, b;
set<int>s;

void dfs(int i1, int cnt1)
{
	if (i1 > cnt)
		{
			if (cnt1 == num)//当选取的数对于num时
				{
					ll sum = 0, tmp = 0;
					for (int i = 0; i < n; ++i)
						{
							if (a[i] == b[i] || vis[a[i] - 'a'])sum++;
							else tmp += (sum) * (sum + 1) / 2, sum = 0;

						}
					tmp += sum * (sum + 1) / 2;
					ans = max(tmp, ans);
				}
		}
	else
		{
			dfs(i1 + 1, cnt1);
			vis[x[i1]] = 1;//标记x数组的这个数选了
			if (cnt1 < num)dfs(i1 + 1, cnt1 + 1);//只有选取的数小于需要的数量时才选
			vis[x[i1]] = 0;

		}
}

int main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--)
		{
			memset(vis, 0, sizeof(vis));
			s.clear();
			cin >> n >> k >> a >> b;
			cnt = 0;
			for (int i = 0; i < n; ++i)
				{
					int tmp = a[i] - 'a';
					if (!s.count(tmp))x[++cnt] = tmp, s.insert(tmp);//记录a中不同的字母数
				}
			ans = 0;
			num = min(k, cnt);
			dfs(1, 0);
			cout << ans << endl;
		}
	return 0;
}

Codeforces Round #849 (Div. 4)G2. Teleporters (Hard Version)

思路:

1,我们每一步都希望走最小的点,所以每个点都取min(a[i]+i,a[i]+n-i+1)。

2,但是,第一步只能从0出发,即第一步只能取a[i]+i,显然我们需要遍历所有第一步,之后的步数就是对除了第一步来到的点之外的点尽可能多的走,我们会发现,每次遍历第一步,后面步数基本是重复剩下几个步数小的点。

3,所以我们可以把所以点的最小步数排序(同时记录他的第一步的步数),计算前缀和,这样我们二分答案即可,如果第一步的点在选择的前几个点里面,减去即可。

#include <bits/stdc++.h>
using namespace std;
#define ll     long long
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
typedef pair<int, int> pii;

//double 型memset最大127,最小128
//std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;

pair<int, int>a[N];
ll sum[N];

int main()
{
	int t, n, x, c;
	cin >> t;
	while (t--)
		{
			cin >> n >> c;
			int ans = 0;
			for (int i = 1; i <= n; ++i)
				{
					cin >> x;
					a[i].first = x + min(i, n - i + 1);
					a[i].second = x + i;
				}
			sort(a + 1, a + 1 + n);//对每个点的最小步排序
			for (int i = 1; i <= n; ++i)sum[i] = sum[i - 1] + a[i].first;//记录最小步前缀和
			for (int i = 1; i <= n; ++i)//遍历每个点作为第一步
				{
					int l = 0, r = n;
					while (l <= r)//二分点数
						{
							int mid = (l + r) >> 1;
							ll tmp = sum[mid] + a[i].second;
							int cnt = mid + 1;//cnt记录总共可以走的点数(包括第一步)
							if (i <= mid)tmp -= a[i].first, cnt--;//如果第一步的点在二分的前缀区间,减去a[i].first这个最小步,点数-1
							if (tmp <= c)
								{
									ans = max(ans, cnt);
									l = mid + 1;
								}
							else r = mid - 1;
						}
				}
			cout << ans << endl;
		}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值