2026马蹄杯

MC0584 蒙嘉受赂通关

本题学到了 \(\mathcal{O(n)}\) 内求出本质不同的回文子串以及统计各个字符出现次数

这里使用的是manacher+字符串哈希

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+5;
char s[N],s1[N<<1];
int n,p[N<<1],cnt,r,mid,sum[N<<1];
int ddd[N<<1];
struct font{
	ll tot;
	char ch;
	bool operator<(const font& b) const{
		return tot==b.tot? ch<b.ch:tot<b.tot;
	}
}ans[30];
int num;
int usd[30];
#define ull unsigned long long
const int P=131;
ull hsh[N<<1],pw[N<<1];
unordered_map<ull,bool> mp;

ull calc(int l,int r){
	return hsh[r]-pw[ddd[r]-ddd[l-1]]*hsh[l-1];
}

int h(char ch){
	if(ch>='a'&&ch<='z')return ch-'a';
	return -1;
}

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
	cin>>(s+1);
	pw[0]=1;
	for(int i=1;i<(N<<1);i++)pw[i]=pw[i-1]*P;
	n=strlen(s+1);
	s1[++cnt]='|';
	for(int i=1;i<=n;i++){
		s1[++cnt]=s[i];
		s1[++cnt]='#';
	}
	s1[++cnt]=';';
	for(int i=1;i<=cnt;i++){
		ddd[i]=ddd[i-1];
		if(s1[i]=='#')hsh[i]=hsh[i-1];
		else {hsh[i]=hsh[i-1]*P+s1[i];ddd[i]++;}
	}
	for(int i=1;i<=cnt;i++){
		if(i<=r)p[i]=min(p[mid*2-i],r-i+1);
		if(mp[calc(i-p[i]+1,i+p[i]-1)]==0){
			mp[calc(i-p[i]+1,i+p[i]-1)]=1;
			sum[i-p[i]+1]++;sum[i+p[i]]--;
		}
		while(s1[i-p[i]]==s1[i+p[i]]){
			p[i]++;
			if(mp[calc(i-p[i]+1,i+p[i]-1)]==0){
				mp[calc(i-p[i]+1,i+p[i]-1)]=1;
				sum[i-p[i]+1]++;sum[i+p[i]]--;
			}
		}
		if(p[i]+i>r)r=i+p[i]-1,mid=i;
	}
	for(int i=1;i<=cnt;i++){
		sum[i]+=sum[i-1];
		if(sum[i]){
			if(h(s1[i])>=0){
				if(!usd[h(s1[i])]){num++;usd[h(s1[i])]=num;ans[num].ch=s1[i];}
				ans[usd[h(s1[i])]].tot+=sum[i];
			}
		}
	}
	cout<<num<<'\n';
	sort(ans+1,ans+1+num);
	for(int i=1;i<=num;i++)cout<<ans[i].ch<<' ';
	
	return 0;
}

MC0585 舞阳失色退场

这题主要是怎么在 \(\mathcal{O(n\log n)}\) 的时间分解质因数

分解质因数+最小生成树

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
const int V=1e6+5;
#define ll long long
int n,t,a[N],vis[V],p[N],cnt,lst[V],tot,siz[N];
ll ans;
basic_string<int> Q;
struct edge{
	int u,v;
	ll w;
	bool operator<(const edge& b) const{
		return w<b.w;
	}
}e[N*100];
edge mke(int u,int v,ll w){
	edge a;
	a.u=u;a.v=v;a.w=w*(u-v);
	return a;
}
int fa[N];
int find(int x){
	return fa[x]==x? x:fa[x]=find(fa[x]);
}
void unionn(int x,int y){
	x=find(x);y=find(y);
	if(siz[x]>siz[y]){siz[x]+=siz[y];fa[y]=x;}
	else {siz[y]+=siz[x];fa[x]=y;}
}

void init(){
//	vis[1]=1;
	for(int i=2;i<=1e6;i++){
		if(vis[i]==0){
			p[++cnt]=i;vis[i]=i;
		}
		for(int j=1;j<=cnt&&p[j]*i<=1e6;j++){
			vis[i*p[j]]=p[j];
			if(i%p[j]==0)break;
		}
	}
}

signed main(){
	scanf("%d",&t);
	init();
	for(int i=1;i<V;i++)lst[i]=-1;
	while(t--){
		tot=0;ans=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){scanf("%d",&a[i]);}
		if(n==1){printf("0\n");continue;}
		for(int i=1;i<=n;i++){
			int o=vis[a[i]],l=a[i];
			while(l!=1){
				Q+=o;
				if(lst[o]!=-1){
					e[++tot]=mke(i,lst[o],o);
				}
				lst[o]=i;
				while(l%o==0)l/=o;
				o=vis[l];
			}
		}
		for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
		sort(e+1,e+tot+1);
		for(int i=1;i<=tot;i++){
			int u=find(e[i].u),v=find(e[i].v);
			if(u!=v){
				unionn(u,v);
				ans=max(ans,e[i].w);
			}
		}
		if(siz[find(1)]!=n)printf("-1\n");
		else printf("%lld\n",ans);
		for(auto v:Q){lst[v]=-1;}
		Q.clear();
	}
	
	return 0;
}
posted @ 2026-08-27 20:38  dgcsjfs  阅读(10)  评论(0)    收藏  举报