Living-Dream 系列笔记 第58期

Posted on 2024-05-25 23:03  _XOFqwq  阅读(5)  评论(0编辑  收藏  举报

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;
}