【题解】2019CCPC哈尔滨L LRU Algorithm 哈希

LRU算法是指对于一个不断增长的数字序列 a i a_i ai和一个窗口大小 m m m,用窗口按出现顺序维护最新出现的 m m m个不同元素。

多组数据,现在给一个长为 n ( 5000 ) n(5000) n(5000)的数字序列,以及 q ( 2000 ) q(2000) q(2000)次询问。

每次询问给定一个 m i m_i mi和长为 m i m_i mi的队列,问如果对大小为 m m m的窗口执行LRU算法,是否有一个时刻窗口和给定的队列相等。


在容量无限的窗口中对给定序列执行LRU算法,把每个时刻的窗口记录下来,并记录所有前缀哈希值。就相当于得到了对所有窗口大小的哈希值。

对于每个询问,在这个窗口大小的所有历史哈希值中判断待查询队列的哈希值是否出现过。

如果没有一个哈希值与它相等,就证明没有出现过。

如果存在一个哈希值与它相等,为了防止哈希冲突,可以使用双哈希或者保存序列二次判断。


第一次写二次判断哈希,感觉要比双哈希靠谱一些,不过复杂度不好保证。

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 5016, MOD = 1000000007;

int toque[M];
int que[M][M];
ll LRU_hash[M][M];  
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int T = read();
	while(T--)
	{
		int n = read(), q = read();
		memset(que[0], 0, (n+1)*sizeof(que[0][0]));
		for(int i=1, qlen=0; i<=n; ++i)
		{
			memcpy(que[i], que[i-1], (n+1)*sizeof(que[0][0]));
			int now = read(), pos = 0;
			for(int j=1; j<=qlen; ++j)
				if(que[i][j]==now)
					pos = j, j = qlen+1;
			for(int j=(pos?pos:++qlen); j; --j)
				que[i][j] = que[i][j-1];
			que[i][1] = now;

			for(int j=1; j<=n; ++j)
				LRU_hash[i][j] = (LRU_hash[i][j-1]*(n+1)+que[i][j])%MOD;
		}
		while(q--)
		{
			int m = read();
			ll hashv = 0;
			for(int i=1; i<=m; ++i)
			{
				toque[i] = read();
				hashv = (hashv*(n+1)+toque[i])%MOD;
			}
			int suc = 0;
			for(int i=0; i<=n; ++i) if(LRU_hash[i][m]==hashv)
			{
				int flag = 1;
				for(int j=1; j<=m; ++j)
					if(que[i][j]!=toque[j])
						flag = 0, j = m+1;
				if(flag)
					suc = 1, i=n+1;
			}
			printf("%s\n",suc?"Yes":"No" );
		}
	}

    return 0;
}


inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值