P1360 [USACO07MAR]Gold Balanced Lineup G

这篇博客介绍了一种使用动态规划解决的问题:给定每天提升的能力值,求最长的连续几天提升的每种能力相同的天数。通过前缀和和位运算技巧,博主提出了有效的算法思路,并给出了C++实现代码。文章强调了如何利用位运算简化条件判断,并通过位前缀和的差值判断是否存在满足条件的连续子序列。
摘要由CSDN通过智能技术生成

传送门

题意:

有n天,m种能力,每天给你一个数x,每天提升的能力用该数的二进制表示,1为提升,反之则不,问你最长的连续几天提升的每种能力相同的天数。

思路:

对于每一种能力值,可以通过前缀和来计数,而如果第l天到第r天满足要求,设bit[i][j]表示第i天第j种能力值的前缀和,那么显然可以得到: b i t [ r ] [ 1 ] − b i t [ l − 1 ] [ 1 ] = b i t [ r ] [ 2 ] − b i t [ l − 1 ] [ 2 ] = . . . . . . b i t [ r ] [ m ] − b i t [ l − 1 ] [ m ] bit[r][1]-bit[l-1][1]=bit[r][2]-bit[l-1][2]=......bit[r][m]-bit[l-1][m] bit[r][1]bit[l1][1]=bit[r][2]bit[l1][2]=......bit[r][m]bit[l1][m]。进行一个简单的移向,可以得到: b i t [ r ] [ i ] − b i t [ r ] [ 1 ] = b i t [ l − 1 ] [ i ] − b i t [ l − 1 ] [ 1 ] bit[r][i]-bit[r][1]=bit[l-1][i]-bit[l-1][1] bit[r][i]bit[r][1]=bit[l1][i]bit[l1][1],那么思路就明了了:对于每一天,先得到它的位前缀和,然后让这一天的位前缀和的每一位都减去它的第一位的位前缀和,再判断结果是否在之前出现过,若出现过,则更新答案。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define pb push_back 
#define p push
const int mod = 1e8;
ll n,m;
vector<ll>now[100010];
map<vector<ll>,int>vis;

int main()
{
//	freopen("C:\\Users\\76004\\Downloads\\P1360_1.in","r",stdin);
	cin>>n>>m;
	int ans = 0;
	for(int i = 0; i < m; i++)
	{
		now[1].pb(0);
		vis[now[1]] = 1;
	}
	for(int i = 2; i <= n+1; i++)
	{
		ll x;
		cin>>x;
		for(int j = 0; j < m; j++)
		{
			int b = x%2;x>>=1;
			now[i].pb(b);
//			if(i>2)
			now[i][j]+=now[i-1][j];
//			cout<<now[i][j]<<" ";
		}
//		cout<<endl;
		vector<ll>p;
		for(int j = 0; j < m; j++)
		p.pb(now[i][j]-now[i][0]);
		if(vis[p])ans = max(ans,i-vis[p]);
		else vis[p] = i;
	}
	cout<<ans<<endl;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值