挑战赛#20全题解(不是占位)
2025-07-13 22:01:13
发布于:北京
T4只吃了一发罚时(喜)
T1两罚、T3一发(怒)
T6一发(悲)
T1
思路
因为 ,且 与 互质,故有 有 个 因子,然后把开头再分解一下就行。
代码
string s;
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>s;
	n=s[0]-'0';
	while(n%2==0)
	{
		cnt++;
		n/=2;
	}
	cout<<cnt+s.size()-1;
	return 0;
}
T2
思路
直接暴力即可,时间复杂度等于 DFS 的复杂度,为 。
代码
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(i=1;i<=n;i++)cin>>a[i];
	for(i=1;i<n;i++)
	{
		cin>>u>>v;
		E[u].push_back(v);
		E[v].push_back(u);
	}
	for(i=1;i<=n;i++)
	{
		bool f=1;
		for(auto& it:E[i])
		{
			if(a[it]==a[i])
			{
				f=0;
				break;
			}
		}
		cnt+=f;
	}
	cout<<cnt;
	return 0;
}
T3
思路
01 背包 模板题,不必多说。
代码
signed main()
{
	cin>>n>>W;
	for(i=1;i<=n;i++)cin>>w[i]>>v[i];
	for(i=1;i<=n;i++)
    {
    	for(j=W;j>=w[i];j--)f[j]=max(f[j],f[j-w[i]]+v[i]);
	}
	cout<<f[W];
	return 0;
}
T4
思路
明显的,我们要尽可能地把 块合并到另一个 块里。那么在 这样的反转后,就变成了 ,刚好能在左边连上 块。
注意,合并有两种情况:合并到最左边(度小 ),合并到第一个(不是最左边的) 块。求最小即可。
代码
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>s;
	for(i=1;i<n;i++)
	{
		if(s[i]!=s[i-1])
		{
			v.push_back({{l,i-1},s[i-1]});
			if(s[i-1]=='1')
			{
				cnt++;
			}
			l=i;
		}
	}
	if(v.empty())v.push_back({{0,n-1},s[n-1]});
	if((*v.rbegin()).first.second!=n-1)
	{  
		v.push_back({{(*v.rbegin()).first.second+1,n-1},s[n-1]});
		if(s[n-1]==d)cnt++;
	}
	if(v.size()==1)
	{
		cout<<0;
		return 0;
	}
	for(i=1;i<v.size();i++)
	{
		if(v[i].second=='0')continue;
		use++;
		vis[i]=1;
		if(use==m)break;
	}
	for(i=1;i<v.size();i++)
	{
		if(v[i].second=='0')continue;
		if(vis[i]==0)
		{
			d+=2;
			if(i==v.size()-1)d--;
		}
	}
	ans=d+1;//111···000···1···1···,统计的时候没统计第一个快,所以得加一
	use=d=0;
	memset(vis,0,sizeof(vis));
	int f1=v.size();
	for(i=1;i<v.size();i++)
	{
		if(v[i].second=='1')
		{
			f1=i;
			break;
		}
	}
	for(i=f1+1;i<v.size();i++)
	{
		if(v[i].second=='0')continue;
		use++;
		vis[i]=1;
		if(use==m)break;
	}
	for(i=0;i<v.size();i++)
	{
		if(v[i].second=='0')continue;
		if(vis[i]==0)
		{
			d+=2;
			if(i==v.size()-1||i==0)d--;
		} 
	}
	ans=min(ans,d);
	cout<<ans;
	return 0;
}
T5
思路
将入场和退场时间排序,亦个处理。
使用 multiset 维护能力值,如果有人入场,那么检查它是否大于等于最小能力的人(贪心选择),如果这都不行就能力值 ,否则计算。将能力放入 multiset 中。退场就从 multiset 中移除对应人的能力值。最后输出就行。
代码
multiset<int> ms;
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(i=1;i<=n;i++)
	{
		cin>>w[i]>>s[i]>>t[i];
		p[++tot]={{s[i]*10,0},i};//*10不用double
		p[++tot]={{t[i]*10+1,1},i};//*10不用double
	}
	sort(p+1,p+tot+1);
	for(i=1;i<=tot;i++)
	{
		int tp=p[i].first.second,id=p[i].second;
		if(tp==1)
		{
			auto it=ms.find(w[id]);
			if(it!=ms.end())ms.erase(it);
		}
		else
		{
			if(!ms.empty())
			{
				if((*ms.begin())<=w[id])ans[id]=w[id]-(*ms.begin());
			}
			ms.insert(w[id]);
		}
	}
	for(i=1;i<=n;i++)cout<<ans[i]<<" ";
	return 0;
}
T6
思路
考虑序列之王 FHQ-Treap(对,不是 Splay 因为我不会),排名分裂和懒标记平衡树的练习。
操作 只要把前 个裂成 ,剩下后 就是 ,合并 和 就行。
操作  给每个节点加个懒标记(偏移),分裂合并的时候 pushdown(下发) 和 pushup(更新大小) 就行。
代码
struct Node
{
	int ls,rs,pri,sz,off;
	char val;
}t[2000005];
int build(char x)
{
	t[++cnt].sz=1;
	t[cnt].ls=t[cnt].rs=t[cnt].off=0;
	t[cnt].val=x;
	t[cnt].pri=rand()*rand();
	return cnt;
}
void update(int u)//pushup
{
	t[u].sz=t[t[u].ls].sz+t[t[u].rs].sz+1;
}
void pushdown(int u)
{
	if(!u)return;
	if(t[u].off)
	{
		if(t[u].ls)t[t[u].ls].off=(t[u].off+t[t[u].ls].off)%26;
		if(t[u].rs)t[t[u].rs].off=(t[u].off+t[t[u].rs].off)%26;
		int add=(t[u].off+26)%26;
		char newc='a'+(t[u].val-'a'+add)%26;
		if(newc>'z')newc-=26;
		else if(newc<'a')newc+=26;
		t[u].val=newc;
		t[u].off=0;
	}
}
void split(int u,int x,int& L,int& R)
{
	if(!u)
	{
		L=R=0;
		return ;
	}
	pushdown(u);
	if(t[t[u].ls].sz+1<=x)
	{
		L=u;
		split(t[u].rs,x-t[t[u].ls].sz-1,t[u].rs,R);
	}
	else
	{
		R=u;
		split(t[u].ls,x,L,t[u].ls);
	}
	update(u);
}
int merge(int L,int R)
{
	if(L==0||R==0)return L+R;
	if(t[L].pri>t[R].pri)
	{
		pushdown(L);
		t[L].rs=merge(t[L].rs,R);
		update(L);
		return L;
	}
	pushdown(R);
	t[R].ls=merge(L,t[R].ls);
	update(R);
	return R;
}
void output(int u)
{
	if(!u)return ;
	pushdown(u);
	output(t[u].ls);
	cout<<t[u].val;
	output(t[u].rs); 
}
string s;
signed main()
{
	srand(time(NULL));
	cin>>n>>s>>q;
	for(i=0;i<n;i++)root=merge(root,build(s[i]));
	while(q--)
	{
		cin>>op;
		if(op==1)
		{
			cin>>l>>r>>x;
			split(root,l-1,L,R);
			split(R,r-l+1,p,R);
			if(p)
			{
				t[p].off=(t[p].off+(x%26))%26;
				if(t[p].off<0)t[p].off+=26;
			}
			root=merge(merge(L,p),R);
		}
		else
		{
			cin>>x;
			x%=n;
			if(x==0)continue;
			split(root,n-x,L,R);
			root=merge(R,L);
		}
	}
	output(root);
	return 0;
}
彩蛋


最终:

全部评论 16
2025-07-13 来自 北京
1cjdst是谁
2025-07-17 来自 浙江
0大概是T5唯一一个橙题解法了(
2025-07-16 来自 湖南
0%%%
2025-07-16 来自 北京
0但
t[i]*10+1意义不明2025-07-16 来自 湖南
0其实是
2025-07-16 来自 北京
0
我竟然写出了T6最复杂、慢的解法!但是可以拓展到操作二为区间时
2025-07-15 来自 北京
0%%%
2025-07-16 来自 湖南
0
%%%
2025-07-15 来自 广东
0《真正的高手,往往只会用最接地气的方式聊天》
2025-07-14 来自 江苏
0%%%
2025-07-14 来自 北京
0%%%
2025-07-13 来自 湖南
0T4代码不用这么长
2025-07-13 来自 浙江
0#include<bits/stdc++.h> using namespace std; int n, m, w[5005]; long long v[5005], f[20005]; int main(){ cin >> n >> m; for(int i = 1; i <= n; i++) cin >> w[i] >> v[i]; for(int i = 1; i <= n; i++){ for(int j = m; j >= w[i]; j--){ f[j] = max(f[j], f[j - w[i]] + v[i]); } } long long ans = 0; for(int j = 0; j <= m; j++) ans = max(ans, f[j]); cout << ans; return 0; }2025-07-13 来自 浙江
0这是赛时T4吗,我说的是赛时T4,不是现在打乱后的T4
2025-07-13 来自 北京
0
@AAA混泥土批发ppl哥桂物出来叫!
2025-07-13 来自 北京
0555
2025-07-14 来自 浙江
0
%%%
2025-07-13 来自 江苏
0%%% orz
2025-07-13 来自 浙江
0沙发!大佬!
2025-07-13 来自 浙江
0
2025-07-13 来自 浙江
0我不会!
2025-07-13 来自 浙江
0求T4答案!!!
2025-07-13 来自 浙江
0比赛未结束
2025-07-13 来自 浙江
2比赛都还在打就敢要答案,唐
2025-07-13 来自 浙江
2第一次见到比 @Lyzc0dr 还唐的入!(((
2025-07-13 来自 浙江
0




































有帮助,赞一个