Educational Codeforces Round 110 (Rated for Div. 2)

E. Gold Transfer

题目描述

点此看题

解法

贪心的看,我们一定是从最浅的祖先开始选起走的。

然后我就想到了树上前缀和,找到刚好选完的那个临界点,用倍增实现。

但是这道题的点是动态加入的,所以前缀和维护不了。有一个极好的均摊分析做法,我们每次就找到最浅的有金子的祖先,然后只考虑它这个单点,要么它被买完,要不我们的购买完成,所以总操作数是 O(q) 的。

那么时间复杂度 O(qlogq),简单倍增即可实现。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 300005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int q,a[M],c[M],fa[M][20];
void work(int x,int y)
{
	int r1=0,r2=0;
	while(a[x]>0 && y>0)
	{
		int t=x;
		for(int i=19;i>=0;i--)
			if(a[fa[t][i]]) t=fa[t][i];
		int tmp=min(a[t],y);
		a[t]-=tmp;y-=tmp;
		r1+=tmp;r2+=tmp*c[t];
	}
	cout<<r1<<" "<<r2<<endl;
	fflush(stdout);
}
signed main()
{
	cin>>q>>a[1]>>c[1];
	for(int n=2;n<=q+1;n++)
	{
		int op;cin>>op;
		if(op==1)
		{
			cin>>fa[n][0]>>a[n]>>c[n];
			fa[n][0]++;
			for(int i=1;i<=19;i++)
				fa[n][i]=fa[fa[n][i-1]][i-1];
		}
		else
		{
			int x,y;cin>>x>>y;x++;
			work(x,y);
		}
	}
}

F. String Distance

题目描述

点此看题

解法

我们只讨论字符集合相同的字符串,记长度为 m,此时 f(s,t) 只有两种取值,讨论一下这两种情况:

  • 如果某个子串 [l,r] 是有序的,并且两个串满足 [1,l),(r,n] 都相等,答案是 1
  • 否则答案是 2

我们找出第一种情况个数即可,我们把同一集合里面的所有串先按字典序排序,对于区间 [1,l) 相同的若干个串,[l,r] 有序的一定排在前面,所以我们可以让 s=ai,t=aj(j>i) 来统计答案。

我们固定 s 的某个极长有序区间,然后统计去掉这个区间后字符串相同 t 的个数。可以把前缀后缀的相等分开考虑,按字典序排序后前缀的变化是连续的,也就是 ai+1...anailcp 是单调不降的,并且 aiajlcp 可以表示为 mink=ij1lcp(k,k+1),所以可以维护一个单调栈,每次把栈顶 lcp 大于等于当且 lcp 的元素弹掉即可。

那么对于单调栈里面元素代表的区间 [x,y]ax...ayai 有相同的 lcp 记为 p,可以借助预处理找到极长有序区间 (p,q],然后找 ax...ayai 满足 (q,m] 这个后缀相同的个数。可以把反串插入 tire 树中,每个节点上维护一个 vector,定位到 tire 上面节点后二分找即可。

时间复杂度 O(|si|log|si|)代码里面用了好多 vector

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
const int M = 200005;
#define int long long
#define pii pair<int,int>
#define make make_pair
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,cnt,ans,sum,ch[M][26];
vector<int> id[M],pos[M];map<string,vector<string>>mp;
//tire
void ins(string s,int x)
{
	pos[x].clear();
	for(int i=0;i<=m;i++) pos[x].push_back(0);
	id[1].push_back(x);
	pos[x][m]=1;
	for(int i=m-1,p=1;i>=0;i--)
	{
		int c=s[i]-'a';
		if(!ch[p][c]) ch[p][c]=++cnt;
		p=ch[p][c];
		pos[x][i]=p;
		id[p].push_back(x);
	}
}
int ask(int p,int l,int r)
{
	return lower_bound(id[p].begin(),id[p].end(),r)-
	lower_bound(id[p].begin(),id[p].end(),l);
}
//solve
int solve(vector<string> a)
{
	//init
	n=a.size();m=a[0].size();
	sort(a.begin(),a.end());
	for(int i=0;i<=cnt;i++)
	{
		for(int j=0;j<26;j++) ch[i][j]=0;
		id[i].clear();
	}
	cnt=1;
	for(int i=0;i<n;i++) ins(a[i],i);
	//work for ordered subsequence
	vector<int> dec[n];
	for(int i=0;i<n;i++)
	{
		for(int j=1;j<m;j++)
			if(a[i][j-1]>a[i][j])
				dec[i].push_back(j);
		dec[i].push_back(m);
	}
	//work for lcp
	vector<int> lcp(n);
	for(int i=1;i<n;i++)
	{
		int j=0;
		while(j<m && a[i][j]==a[i-1][j]) j++;
		lcp[i]=j;
	}
	//cal
	int res=n*(n-1);
	vector<pii> stk;stk.push_back(make(n,-1));
	for(int i=n-1;i>=0;i--)
	{
		for(int j=1;j<stk.size();j++)
		{
			int l=stk[j].first,r=stk[j-1].first,p=stk[j].second;
			p=*upper_bound(dec[i].begin(),dec[i].end(),p);
			res-=ask(pos[i][p],l,r);
		}
		while(stk.back().second>=lcp[i]) stk.pop_back();
		stk.push_back(make(i,lcp[i]));
	}
	return res;
}
signed main()
{
	k=read();
	for(int i=0;i<k;i++)
	{
		string s,t;
		cin>>s;t=s;
		sort(t.begin(),t.end());
		mp[t].push_back(s);
	}
	for(auto it:mp)
	{
		vector<string> a=it.second;
		ans+=1337*a.size()*sum;
		ans+=solve(a);
		sum+=a.size();
	}
	printf("%lld\n",ans);
}
posted @   C202044zxy  阅读(79)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示