zoukankan      html  css  js  c++  java
  • Luogu P2843 暗杀

    原题链接https://www.luogu.org/problem/P2843

    题目描述

    敌方的高级将领都是有很多相同之处的。为了方便找到每名敌将的弱点,我军情报部已经找到了他们的不同点,并将其归纳为K种特性。比如1号特性就代表一个敌将喜欢打人,2号特性就代表一个敌将喜欢吃饭,等等。

    为了方便存储,我军使用特性值来描述一个敌将的特点。特性值是一个位数为K的二进制整数,每一位都可以表示一名敌将的一个特性。1代表具有此特性,0代表没有。

    我军间谍打听到,不久有N个敌方将领会举行一场宴会,而且入场时他们会排成一路纵队入场。如果有连续的M个人的每种特性出现的次数之和是一样的,那么我军间谍就很容易暗杀这M个人。你需要帮助我军算出,间谍最多可以暗杀多少人?

    因为间谍开始攻击后就可能被敌人击毙,所以间谍只能进行一次攻击。

    样例说明:
    ai         属性           敌将
    7          1 1 1            1
    6          0 1 1            2
    7          1 1 1            3
    2          0 1 0            4
    1          1 0 0            5
    4          0 0 1            6
    2          0 1 0            7
    可以击杀第3人到第6人,共6-3+1=4人
    

    由题意可知我们要找到一段区间其中各个特征和相等,用一个sum数组记录各个特征的前缀和,我们可以得出如果区间[l, r]中各个特征和相等, 那么

    [sum[l][2] - sum[l][1] = sum[r][2] - sum[r][1] ]

    [sum[l][3] - sum[l][1] = sum[r][3] - sum[r][1] ]

    ​ ....

    证明:

    当区间[l, r]中各个特征和相等, 设和的值为x

    [sum[r][1] = sum[l][1] + x ]

    [sum[r][2] = sum[l][2] + x ]

    ​ ...

    所以前缀和的相对差值不变。
    将前缀和相对差值进行hash,映射到数组中然后用hash值作为key进行匹配,最后进行差值比较确认是否符合。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #define ll long long
    using namespace std;
    
    const int N = 1e5 + 10, M = 40, MAX = 1e6 + 10; 
    
    int n, k, ans, num;
    int lg[M];
    int a[N][M], sum[N][M];
    
    vector<int>	 hash[MAX];
    
    template <typename T>
    inline void read(T &x){
    	x = 0;
    	char c = getchar();
    	T op = 1;
    	for(; c < '0' || c > '9'; c = getchar())
    		if(c == '-')	op = -1;
    	for(; c <= '9' && c >= '0'; c = getchar())
    		x = (x << 3) + (x << 1) + c - '0';
    	x *= op;
    }
    
    inline bool check(int x, int y){
    	for(int i = 1; i <= k; ++i)
    		if(a[x][i] != a[y][i])	return 0;
    	return 1;
    }//进行精准检验
    
    inline void HASH(int x){
    	int p = 0;
    	for(int i = 1; i <= k; ++i)
    		p += a[x][i] * lg[i], p %= MAX;
    	p = (p + MAX) % MAX;
    	int s = hash[p].size();
    	for(int i = 0; i < s; ++i) //在这人之前是否可以找到一个人进行匹配
    	if(ans < (x - hash[p][i]))
    		if(check(x, hash[p][i]))	
    			ans = x - hash[p][i];
    	hash[p].push_back(x);
    	return;
    }//加入到key为p的hash数组中
    
    inline void init(){
    	read(n), read(k);
    	ans = 0, lg[1] = 1;
    	for(int i = 2; i <= k; ++i)	lg[i] = (lg[i - 1] * 71) % MAX;
    	hash[0].push_back(0); //要对第一个人就符合条件进行判断
    }
    
    int main(){
    	init();
    	for(int i = 1; i <= n; ++i){
    		read(num);
    		for(int j = 1; j <= k; ++j, num >>= 1) //进行数字分解并进行前缀和计算
    			sum[i][j] = sum[i - 1][j] + (num & 1), a[i][j] = sum[i][j] - sum[i][1]; // 计算相对差值
    		HASH(i);
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Windows核心编程笔记:同步设备I/O与异步设备I/O 200404
    最顶层窗口
    Windows环境变量
    如何使用Beyond Compare比较两个文件夹的差异
    c++生成缩略图
    MD5加密算法
    c++读写注册表
    通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号
    Hive中HSQL中left semi join和INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN区别
    postgreSQL格式化时间的函数详解
  • 原文地址:https://www.cnblogs.com/ZmeetL/p/11801446.html
Copyright © 2011-2022 走看看