zoukankan      html  css  js  c++  java
  • 计蒜客 UCloud 的安全秘钥(随机化+Hash)

    题目链接 UCloud 的安全秘钥

    对于简单的版本,我们直接枚举每个子序列,然后sort一下判断是否完全一样即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N = 200010;
    
    int n;
    int a[N], b[N], c[N];
    int m,q;
    
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n) scanf("%d", a + i);
    
    	scanf("%d", &q);
    
    	while (q--){
    		scanf("%d", &m);
    		rep(i, 1, m) scanf("%d", b + i);
    
    		if (m > n){
    			puts("0");
    			continue;
    		}
    
    		sort(b +1, b  + m + 1);
    
    		int ans = 0;
    
    
    		rep(i, 1, n - m +1){
    			rep(j, 1, m) c[j] = a[i + j - 1];
    			sort(c + 1, c + m + 1);
    			bool fl = true;
    			rep(j, 1, m) if (c[j] != b[j]){
    				fl = false;
    				break;
    			}
    
    			if (fl) ++ans;
    		}
    
    		printf("%d
    ", ans);
    	}
    
    
    	return 0;
    
    }
    

    对于中等版本,这个时候不能在判断两个序列是否相似上面花太多的条件。

    这个时候就想到了Hash

    对$1$到$n$的每一个数,随机一个权值。

    两个序列相似则有这两个序列的每个元素的Hash和相等

    那么就可以维护一个Hash值的前缀和,判断的时候$O(1)$完成。

    但Hash和相等只是必要条件,并不是充分条件,当数据大的时候很容易出错。

    所以我随机了四组Hash值,仅当四组Hash值都与原串相等时才算相似。

    这样出错概率就基本为零了

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N = 50010;
    const long long mod = 1000007;
    
    int n;
    long long w1[N], w2[N], w3[N], w4[N];
    long long c1[N], c2[N], c3[N], c4[N];
    int a[N];
    int q, m;
    int b[N << 2];
    
    
    int main(){
    
    
    	srand(0);
    	scanf("%d", &n);
    
    	rep(i, 1, n) w1[i] = rand() % mod;
    	rep(i, 1, n) w2[i] = rand() % mod;
    	rep(i, 1, n) w3[i] = rand() % mod;
    	rep(i, 1, n) w4[i] = rand() % mod;
    
    
    	rep(i, 1, n) scanf("%d", a + i);
    
    	scanf("%d", &q);
    	while (q--){
    
    		int ans = 0;
    		scanf("%d", &m);
    		rep(i, 1, m) scanf("%d", b + i);
    		long long st1 = 0, st2 = 0, st3 = 0, st4 = 0;
    		rep(i, 1, m){
    			st1 += w1[b[i]];
    			st2 += w2[b[i]];
    			st3 += w3[b[i]];
    			st4 += w4[b[i]];
    		}
    
    		memset(c1, 0, sizeof c1);
    		memset(c2, 0, sizeof c2);
    		memset(c3, 0, sizeof c3);
    		memset(c4, 0, sizeof c4);
    
    
    		rep(i, 1, n){
    			c1[i] = c1[i - 1] + w1[a[i]];
    			c2[i] = c2[i - 1] + w2[a[i]];
    			c3[i] = c3[i - 1] + w3[a[i]];
    			c4[i] = c4[i - 1] + w4[a[i]];
    		}
    
    		rep(i, 1, n - m + 1){
    			long long n1 = c1[i + m - 1] - c1[i - 1];
    			long long n2 = c2[i + m - 1] - c2[i - 1];
    			long long n3 = c3[i + m - 1] - c3[i - 1];
    			long long n4 = c4[i + m - 1] - c4[i - 1];
    			if (n1 == st1 && n2 == st2 && n3 == st3 && n4 == st4) ++ans;
    		}
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    
    }
    

    对于困难版本,如果m比较小,则枚举连续子序列的时间会很长。

    那么考虑把m小的时候的答案全部塞到map里,询问的时候直接拿出来。

    不过Hash的时候还是要保证至少两组,不然出错的概率相当大。

    我也是调了好久才卡过去的QAQ

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    typedef long long LL;
    
    const int L  = 2;
    const int N  = 50010;
    const LL mod = 1000000007;
    
    int S = 10;
    int n, m, q;
    int a[N];
    LL Hash[N][L << 1];
    LL c[N][L << 1], s[N][L << 1];
    LL hash_now[L << 1];
    map <LL, int> mp[20][L << 1];
    
    int main(){
            
    	scanf("%d", &n);
    	rep(i, 1, n) scanf("%d", a + i);
    
    	srand(time(0));
    	rep(op, 0, L - 1){
    		rep(i, 1, n){
    		       Hash[i][op] = (LL)rand();
    		}
    	}
    
    	
    	rep(i, 1, n){
    		rep(j, 0, L - 1){
    			c[i][j] = Hash[a[i]][j];
    			s[i][j] = s[i - 1][j] + c[i][j];
    
    		}
    	}
    
    
    	S = min(S, n);
    	rep(len, 1, S){
    		rep(i, 1, n - len + 1){
    			rep(j, 0, L - 1){
    				++mp[len][j][s[i + len - 1][j] - s[i - 1][j]];
    		
    			}
    		}
    	}
    
    	for (scanf("%d", &q); q--;){
    		scanf("%d", &m);
    		memset(hash_now, 0, sizeof hash_now);
    
    		rep(i, 1, m){
    			int x;
    			scanf("%d", &x);
    			rep(j, 0, L - 1) hash_now[j] += Hash[x][j];
    		}
    
    		if (m <= S){
    			int ans = 1 << 30;
    			rep(i, 0, L - 1) ans = min(ans, mp[m][i][hash_now[i]]);
    			printf("%d
    ", ans);
    			continue;
    		}
    
    		if (m > n){
    			puts("0");
    			continue;
    		}
    
    		int ans = 0;
    			
    		rep(i, 1, n - m + 1){
    			bool fl = true;
    			rep(j, 0, L - 1) if (s[i + m - 1][j] - s[i - 1][j] != hash_now[j]) fl = false;
    			if (fl) ++ans;
    		}
    
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Cocos 更新时反复杀进程,导致差异更新失效的Bug
    Cocos 编译android-studio
    Could not resolve all dependencies for configuration ':classpath'
    MAC Gradle 下载的问题
    命令行创建 keystore
    应用间共享文件 FileProvider
    Android jks 签名文件 生成
    Gradle 离线 安装
    信息
    Cocos Lua的Touch 点击事件添加
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7226703.html
Copyright © 2011-2022 走看看