2024暑期集训补题(倍增)

牛客多校3 J题

在这里插入图片描述
题意:
B O 2 b − 1 BO 2b-1 BO2b1 B O 2 a − 1 BO 2a-1 BO2a1赛制,内部是 B O 2 a − 1 BO 2a-1 BO2a1赛制,外部是 B O 2 b − 1 BO 2b-1 BO2b1赛制,给定 n n n长度的 01 01 01串, 0 0 0表示输, 1 1 1表示赢。问从 i i i位置开始,不断循环完整的该字符串结果,问最终每个位置 i i i开始比赛时,整个比赛的最终结果是 1 1 1还是 0 0 0

题解:
先考虑从 i i i位置开始的内部的 B O 2 a − 1 BO 2a - 1 BO2a1赛制结果,显然利用双指针,左端表示开始的位置,右端表示从开始的位置比赛后的内部赛的结果的位置,当左端点向右移动时,我们需要移动右端点直到比赛比出胜负,然后初始化倍增数组,将开始位置向右跳一步到比出胜负的下一步的过程设置为 f [ i ] [ 0 ] = j f[i][0] = j f[i][0]=j,同时用一个二维 s u m sum sum数组表示倍增过程中的胜负的次数统计。
然后再用 f [ i ] [ 0 ] , s u m [ i ] [ 0 ] f[i][0],sum[i][0] f[i][0],sum[i][0]表示出所有的 f [ n ] [ 20 ] , s u m [ n ] [ 20 ] f[n][20],sum[n][20] f[n][20],sum[n][20]状态,最后从每个 i i i开始,贪心向右跳,如果要跳的步数小于等于外部赛制的最大局数 2 ∗ b − 1 2*b - 1 2b1,那么就跳,同时统计 s u m sum sum中赢的场次。最后比较胜利的场次是否大于等于 b b b即可。

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define debug(p) for(auto i : p)cerr << i << " "; cerr << endl;
#define debugs(p) for(auto i : p)cerr << i.first << " " << i.second << endl;
typedef pair<int, int> pll;
string yes = "YES";
string no = "NO";
constexpr int N = 1e5 + 7;
int f[N][22];
int sum[N][22];
void solve()
{
	int n, a, b;
	cin >> n >> a >> b;
	string s;
	cin >> s;
	int cnt[2] = {0, 0};
	for (int i = 0, j = 0; i < n; i++)
	{
		while(cnt[0] < a && cnt[1] < a)
		{
			cnt[s[j] - '0']++;
			j = (j + 1) % n;
		}
		f[i][0] = j;
		sum[i][0] = (cnt[1] > cnt[0]);
		cnt[s[i] - '0']--;
	}
	for (int i = 1; i < 20; i++)
	{
		for (int j = 0; j < n; j++)
		{
			sum[j][i] = sum[j][i - 1] + sum[f[j][i - 1]][i - 1];
			f[j][i] = f[f[j][i - 1]][i - 1];
		}
	}
	for (int i = 0; i < n; i++)
	{
		int win = 0, pos = i, rest = 0;
		for (int j = 19; j >= 0; j--)
		{
			if(rest + (1ll << j) <= 2 * b - 1)
			{
				rest += (1ll << j);
				win += sum[pos][j];
				pos = f[pos][j];
			}
		}
		if(win >= b)cout << 1;
		else cout << 0;
	}
	cout << endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int T = 1;
	// cin >> T;
	while(T--)
	{
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值