zoukankan      html  css  js  c++  java
  • NOI2017 蚯蚓排队

    发现自己哈希的无数个问题……

    首先蚯蚓可以用链表维护这个序列。

    然后发现 (k) 很少,意味着每次合并或删除所动的子串数量非常少。这启发我们可以把所有出现的长度 (le k) 的子串全部通过哈希塞进一个桶里面,然后查询的时候我们直接再桶中查询。

    对于如何维护这个桶,我们可以用一个散列表。

    具体一点的操作。对于合并,我们找到第一个队伍靠近尾巴的 (k) 个和第二个队伍的靠近头的 (k) 个,然后找到所有由两边合并所得到的子串,哈希值丢进散列。

    对于删除,我们同样的这样操作,把两边合并得到的子串给从散列中扔出来。也就是合并的逆操作。

    对于查询,对于每一个长 (k) 的子串,在散列表中查询即可。

    分享一个关于我的哈希的故事:我一开始用了一个单模数的哈希,被卡了;然后用了一个双模的,TLE 了;然后发现哈希应该把哈希和长度当成一个 pair 去比较,然后被卡了;然后我换成自然溢出,AC 了。。

    实际上这样是正常的。自然溢出比 32 位整型模数的容量大一倍,然后哈希的值存成一个由哈希值和长度组成的 pair 的话也可以大大降低被卡率。至于双模 TLE 的问题,多半是我人傻常熟大 /qd。

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    typedef pair<int,int> pii;
    typedef vector<int> vi;
    typedef unsigned long long ull;
    typedef pair<ull,int> pui;
    
    long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48, c=getchar();}
    	return res*w;
    }
    
    const int N=2e5+9,mod=20070720+20061019+5250,base=131,dom=998244353;
    
    int n,m,len[N],a[10000001],cnt[9];
    char s[10000001];
    ull b[N];
    
    
    int pre[N],nxt[N];
    void cut(int x) {pre[nxt[x]]=0,nxt[x]=0;}
    void unite(int x,int y) {nxt[x]=y,pre[y]=x;}
    
    namespace HT {
    	int hd[mod],nxt[mod],c[mod],tot;
    	pui vp[mod];
    	void add(pui x) {
    		int val=x.fi%mod,u=hd[val];
    		while(u&&vp[u]!=x) u=nxt[u];
    		if(!u) {vp[++tot]=x,c[tot]=1,nxt[tot]=hd[val],hd[val]=tot;}
    		else c[u]++;
    	}
    	void del(pui x) {
    		int val=x.fi%mod,u=hd[val];
    		while(u&&vp[u]!=x) u=nxt[u];
    		if(!u) throw 404;
    		else c[u]--;
    	}
    	int qry(pui x) {
    		int val=x.fi%mod,u=hd[val];
    		while(u&&vp[u]!=x) u=nxt[u];
    		return c[u];
    	}
    }
    
    int main() {
    	n=read(), m=read();
    	rep(i,1,n) len[i]=read(), cnt[len[i]]++;
    	b[0]=1; rep(i,1,100) b[i]=b[i-1]*base;
    	rep(i,1,m) {
    		int opt=read();
    		if(opt==1) {
    			int x=read(), y=read();
    			vi f(101); vector<ull> g(101);
    			for(int u=x,c=50;c;u=pre[u]) f[c--]=u;
    			for(int u=y,c=50;c<=100;u=nxt[u]) f[++c]=u;
    			rep(i,1,100) g[i]=g[i-1]*base+len[f[i]];
    			rep(l,1,50) if(f[l]) rep(r,51,100) if(f[r]&&r-l+1<=50) {
    				ull res=g[r]-g[l-1]*b[r-l+1];
    				HT::add(pui(res,r-l+1));
    			}
    			unite(x,y);
    		} else if(opt==2) {
    			int x=read(), y=nxt[x];
    			cut(x);
    			vi f(101); vector<ull> g(101);
    			for(int u=x,c=50;c;u=pre[u]) f[c--]=u;
    			for(int u=y,c=50;c<=100;u=nxt[u]) f[++c]=u;
    			rep(i,1,100) g[i]=g[i-1]*base+len[f[i]];
    			rep(l,1,50) if(f[l]) rep(r,51,100) if(f[r]&&r-l+1<=50) {
    				ull res=g[r]-g[l-1]*b[r-l+1];
    				HT::del(pui(res,r-l+1));
    			}
    
    		} else {
    			scanf("%s",s+1); int m=strlen(s+1), k=read();
    			rep(i,1,m) a[i]=s[i]-'0';
    			int ans=1;
    			if(k==1) {
    				rep(i,1,m) ans=1ll*ans*cnt[a[i]]%dom;
    				printf("%d
    ",ans);
    				continue;
    			}
    			vector<ull> g(m+1);
    			rep(i,1,m) g[i]=g[i-1]*base+a[i];
    			rep(l,1,m-k+1) {
    				int r=l+k-1; ull res=g[r]-g[l-1]*b[r-l+1];
    				ans=1ll*ans*HT::qry(pui(res,k))%dom;
    			}
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    HAService 刨坑
    RocketMQ服务器监控误区
    Send [1] times, still failed
    RECONSUME_LATER
    RocketMQ 自定义文件路径
    RocketMQ 运维指令
    Thrift 学习记录
    服务网格(Service Mesh)学习记录
    Linux 安装 Apache
  • 原文地址:https://www.cnblogs.com/TetrisCandy/p/15382569.html
Copyright © 2011-2022 走看看