lightoj1423Olympic Swimming

思路:有k条长度为l的泳道,每天泳道上面有n[i]个障碍物,w诶了比赛的公平性,每个泳道里面只能有相同数目个障碍物,求最长的泳道。

这样我们可以枚举泳道的右位置,计算出每个泳道中从0到这个位置的障碍物数目,求出最大与最小值。如果相等说明这个位置是目前长的泳道右端点。然后,因为要想等,如果要以这个位置为泳道的右端点,那么我们需要求一个想等的左端点。cnt[i] = A[i][j] - mi;这样的话,障碍物的数目就是mi个,求一个最远的左端点就好了,,,这样就需要hash一下,因为直接找的话时间消耗太大了,这里减了之后就会又一个差值状态,只需要求出这个状态出现的最早的位置就好了,出现过就是端点距离差+1(这里是因为出现了相同的差值状态,说明这两个位置之间的障碍物数目是一样多的,符合要求,可以手算证明下),没有就标记这个状态是在这个位置出现的。因为数字较大,所以要选择一个比较好的hash方法,试了好几个都是wa,看网上的就行了,,,只能说这种hash方式的选择看经验了。

// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
// #define DEBUG
#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__ )
#else
#define debug(...)
#endif
#define CLR(x) memset(x, 0,sizeof x)
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
template<class T> inline T Get_Max(const T&a,const T&b){return a < b?b:a;}
template<class T> inline T Get_Min(const T&a,const T&b){return a < b?a:b;}
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const ULL MOD = (1ULL << 63) - 1;
const int maxn = 5e4 + 10;
map<ULL, int> mp;
int A[maxn][30];
int cnt[30];
void solve(int icase){
	int L, K;
	scanf("%d%d",&L,&K);
	mp.clear();
	memset(A, 0,sizeof A);
	for (int i = 0;i < K;++i){
		int num, p;
		scanf("%d",&num);
		while(num--){
			scanf("%d",&p);
			A[p][i]++;
		}
	}
	int ret=0,p=0;
	for (int i = 0;i < L;++i){
		int mi = L + 1,ma = -1;
		for (int j = 0;j < K;++j){
			if (i) A[i][j] += A[i-1][j];
			mi = min(mi, A[i][j]);
			ma = max(ma, A[i][j]);
		}
		if (mi==ma) ret=i+1;
		for (int j = 0;j < K;++j){
			cnt[j] = A[i][j]-mi;
		}
		// printf("(%d,",ret);
		LL tmp = 0;
		for (int j = K - 1;j >= 0;--j){
			tmp ^= cnt[j];
			tmp *= 12345678;
			// tmp ^= cnt[j];
			// cout << "tmp " << tmp << " ";
			// tmp ^= (1ULL*cnt[j])%MOD;
		}
		int t = mp[tmp];
		if (t){
			ret = Get_Max(ret,i-t+1);
		}else{
			mp[tmp]=i+1;
		}
		// printf("%d)\n",ret);
		// cout << "tmp = " << tmp << endl;
	}
	printf("Case %d: %d meter(s)\n",icase,ret);
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int t, icase = 0;
	scanf("%d",&t);
	while(t--){
		solve(++icase);
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值