首页 > 其他分享 >Living-Dream 系列笔记 第58期

Living-Dream 系列笔记 第58期

时间:2024-05-25 23:12:28浏览次数:30  
标签:Living hash 58 int cin long ht const Dream

T1

第一问开桶统计即可。

第二问我们采用双指针,不断地移动 \(r\) 直到包下含有最多单词数的区间,再移动 \(l\) 使答案更优并不断更新答案即可。

具体有一些细节见代码。时间复杂度 \(O(n \log n)\)。

可以把代码中的两个 map 换成数组存 hash value,时间可以降至 \(O(n)\),但是我懒了。()

code
#include<bits/stdc++.h>
using namespace std;

const int N=1e3+5,M=1e5+5;
int n,m,ans1,ans2=1e9;
map<string,int> vis,cnt;
string a[N],b[M];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],vis[a[i]]=1;
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>b[i];
		if(vis[b[i]]==1) ans1++,vis[b[i]]++;
	}
	if(ans1==0) cout<<0<<'\n'<<0,exit(0);
	int l=1,r=0,tot=0;
	while(r<m){
		while(tot<ans1&&r<m){
			cnt[b[++r]]++;
			if(cnt[b[r]]==1&&vis[b[r]]) tot++;
		}
		while(tot==ans1){
			ans2=min(ans2,r-l+1);
			cnt[b[l]]--;
			if(!cnt[b[l]]&&vis[b[l]]) tot--;
			l++;
		}
	}
	cout<<ans1<<'\n'<<ans2;
	return 0;
}

T2

很容易(?)发现一个性质:一个反对称字符串,去掉它两头的若干个字符,剩下的字符串仍是反对称的。

这启发我们不是去枚举子串,而是去枚举字串的对称轴。

其中对称轴一定位于两个字符之间,因为子串长度必定为偶数(是奇数则中间那个数会被取反,导致整个子串不可能反对称)。

接下来,我们二分子串长度的一半,然后比较子串的 hash value 与 它反对称后的 hash value 是否相等即可完成 check(这两个都可以预处理出来)。

然后对于每个反对称字串,根据我们发现的性质可得,它对答案的贡献即为 \(\frac{len}{2}\)(因为它两头去掉偶数个字符后仍为反对称字符串)。

code
#include<bits/stdc++.h>
#define ull unsigned long long
#define i64 long long
using namespace std;

const int N=5e5+5;
const int BASE=13331;
i64 n,ans;
string s;
ull hs[N],ht[N],p[N];

void init_hash(){
	p[0]=1;
	for(int i=1;i<=n;i++)
		hs[i]=hs[i-1]*BASE+s[i],p[i]=p[i-1]*BASE;
	for(int i=1;i<=n;i++) s[i]=(s[i]=='0'?'1':'0');
	for(int i=n;i>=1;i--)
		ht[i]=ht[i+1]*BASE+s[i];
}
int get_hs(int l,int r){
	return hs[r]-hs[l-1]*p[r-l+1];
}
int get_ht(int l,int r){
	return ht[l]-ht[r+1]*p[r-l+1];
}
bool check(int now,int x){
	int ll=now-x/2+1,rr=now+x/2;
	return get_hs(ll,rr)==get_ht(ll,rr);
}

int main(){
	cin>>n>>s,s='#'+s;
	init_hash();
	for(int i=1;i<n;i++){
		int l=0,r=min((i64)i,n-i)*2+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(check(i,mid)) l=mid;
			else r=mid;
		}
		ans+=l/2;
	}
	cout<<ans;
	return 0;
}

作业 T1

当然你可以用 map 水过,但是这里我们用 hash。

直接预处理每篇文章里每个单词的 hash value,然后对于每个询问,求出当前单词的 hash value 再一一比对即可。

map code
#include<bits/stdc++.h>
using namespace std;
int n,m,l;
map< string,set<int> > ms;
set<int>::iterator it;

int main(){
    cin.tie(nullptr);
    cout.tie(nullptr);
    
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>l;
        for(int k=1;k<=l;k++){ string tmp; cin>>tmp; ms[tmp].insert(i); }
    }
    
    cin>>m;
    for(int i=1;i<=m;i++){
        string tmp; cin>>tmp;
        
        if(ms.count(tmp))
            for(it=ms[tmp].begin();it!=ms[tmp].end();it++) cout<<*it<<' ';
        cout<<'\n';
    }
    return 0;
}
hash code
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;

const int N=5e3+5,M=1e3+5;
const int BASE=13331;
int n,m,l[N];
string s[N][M];

ull hs[N][M];

void init_hash(int i,int j){
	for(int k=0;k<s[i][j].size();k++)
		hs[i][j]=hs[i][j]*BASE+s[i][j][k];
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>l[i];
		for(int j=1;j<=l[i];j++)
			cin>>s[i][j],init_hash(i,j);
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		string ss; cin>>ss;
		ull ss_hash=0;
		for(int j=0;j<ss.size();j++)
			ss_hash=ss_hash*BASE+ss[j];
		for(int j=1;j<=n;j++){
			for(int k=1;k<=l[j];k++){
				if(ss_hash==hs[j][k]){
					cout<<j<<' ';
					break;
				}
			}
		}
		cout<<'\n';
	}
	return 0;
}

作业 T2

二分最后的匹配成功的位置,截取 \(A,B\) 串相应区间比对完成 check,最后用桶统计答案即可。

具体细节见代码。

code
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;

const int N=2e5+5;
const int BASE=13331;
int n,m,q,ans[N];
string a,b;
ull hsa[N],hsb[N],p[N];

void init_hash(){
	p[0]=1;
	for(int i=1;i<=n;i++) hsa[i]=hsa[i-1]*BASE+a[i],p[i]=p[i-1]*BASE;
	for(int i=1;i<=m;i++) hsb[i]=hsb[i-1]*BASE+b[i];
}
ull get_hsa(int l,int r){
	return hsa[r]-hsa[l-1]*p[r-l+1];
}
ull get_hsb(int l,int r){
	return hsb[r]-hsb[l-1]*p[r-l+1];
}

int main(){
	cin>>n>>m>>q>>a>>b;
	a='#'+a,b='#'+b;
	init_hash();
	for(int i=1;i<=n;i++){
		int l=0,r=min(n-i+1,m)+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(get_hsa(i,mid+i-1)==get_hsb(1,mid)) l=mid;
			else r=mid;
		}
		ans[l]++;
	}
	while(q--){
		int x; cin>>x,cout<<ans[x]<<'\n';
	}
	return 0;
}

标签:Living,hash,58,int,cin,long,ht,const,Dream
From: https://www.cnblogs.com/XOF-0-0/p/18213140

相关文章

  • 线段树维护区间字符的两道例题(CF240F CF558E)
    CF240F:https://www.luogu.com.cn/problem/CF240F题目大意:给定一个长为n的由a到z组成的字符串,有m次操作,每次操作将[l,r]的字符串进行重排,得到字典序最小的字符串,输出m次操作后的字符串。大致思路:1.首先我们要想区间内的字典序最小的回文串要怎么构造。回文串无非就两种类型:有一......
  • 1358:中缀表达式值(expr)
    题目网址:信息学奥赛一本通(C++版)在线评测系统题目介绍:1358:中缀表达式值(expr)时间限制:1000ms      内存限制:65536KB提交数:13372   通过数: 4646【题目描述】输入一个中缀表达式(由0-9组成的运算数、加+减-乘*除/四种运算符、左右小括号组成。注意“......
  • NeurIPS ’24 截稿不足 2 天!hyper.ai 汇总 58 个顶会,提供精确到秒的 DDL 倒计时,持续更
    NeurIPS作为人工智能和机器学习领域的顶级会议,备受全球学者的关注。NeurIPS,全称为NeuralInformationProcessingSystemsConference,是神经信息处理系统的年度学术会议。该会议与ICML并称为人工智能领域难度最大、水平最高、影响力最强的会议。今年的NeurIPS会议即将......
  • 力扣2589 5.16
    原题网址:此处为链接个人难度评价:1700分析:原本的想法是按开始时间排序后遍历,然后贪心的把下一段的和这一段的放一起,发现不够放了就把不够的算出来截为新的一段。最后发现其实有后效性。正解的贪心是:按结束时间排序后(当然是升序),贪心的把本段的都放最后。每次放的时候先检查本区......
  • 58同城的登录(RSA算法)
    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解`58同城的登录(RSA算法)日期:2016-11-23阿珏教程浏览:3631次评论:8条58同城的登录(RSA算法)这一次。又是一个精彩的登录算法解析......
  • 3588 音频 alsamixer , amixer ,设置。
    问题:目前客户遇到,再通过alsamixer设置完音频之后,也可以播放音频,但是,所设置的内容,再重新开机之后便会无法保存。解决:首先是网上的资料:https://blog.csdn.net/weixin_47295886/article/details/125372652  这部分我也是可以参考正点原子的手册的。总体的思路是:先利......
  • Living-Dream 系列笔记 第57期
    hashfunction(哈希函数)将一个规模很大的字符串用特定规则转化为特定数值,这种特定规则,我们称之为hashfunction。hashvalue(哈希值)字符串由哈希函数生成的数值。hashcollision(哈希冲突)多个字符串得到了相同的hashvalue。算法竞赛中的hashfunction通常将字符......
  • 【WCH蓝牙系列芯片】-基于CH582开发板—主机枚举从机所有服务和特征
    -------------------------------------------------------------------------------------------------------------------------------------在使用沁恒的CH582蓝牙芯片的过程中,有时需要主机去连接蓝牙从机进行通信,主机在使用过程中工作流程是: 1、 蓝牙初始化完成后,开始扫描......
  • [LeetCode] 1584.连接所有点的最小费用 Kruskal And Prim 算法 Java 并查集
    Problem:1584.连接所有点的最小费用目录Kruskal算法复杂度CodePrim算法复杂度CodeKruskal算法复杂度时间复杂度:添加时间复杂度,示例:$O(mlog(m))$空间复杂度:添加空间复杂度,示例:$O(n)$CodeclassSolution{publicintminCostConnectPoints(int[][]po......
  • CH57x/CH58X/CH59X/CH32F/V208OTA使用说明
    目前提供了两种OTA升级方式,方式一:带库升级;每次升级可以带着库一起进行升级(带库升级适用于flash较大的芯片)方式二:固定库升级;升级时库不会随着升级而升级(适用于flash不够用时)方式一:升级时需要同时烧录这三个固件:(可以使用isp工具同时烧录也可以使用合并工具将三个工程合并后再烧......