Codeforces Round 954 (Div. 3)

T1,T2水题,没啥好说的。T3半水题,T4赛时唐氏,T5有一点想不到。

T3 Update Queries

题意

给一个长度为 n 的字符串 s,一个长度为 m 的字符串 c,以及 m 个指针 indi

你可以任意更改字符串 c 和指针的顺序,然后按顺序执行以下操作:sindi=ci

m 次操作后可以得到的字典序最小的字符串 s。(注意必须从第一次到最后一次执行 m 次操作)

解析

一眼看上去有点麻烦,想一想发现对于同一个 ind,后面的更新会覆盖前面的,所以其实只要记最小的对应的 ci

又因为 c 的顺序可以任意改变,所以实际上就是将 indi 排序,然后每次取最小的 ci。如果重复出现的 indi 直接跳过。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+5;
int t;
int n,m,a[N];
bool vs[N];
string s,c;
 
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		memset(vs,0,sizeof(vs));
		scanf("%d%d",&n,&m);
		cin>>s; s=' '+s;
		for(int i=1;i<=m;i++) scanf("%d",&a[i]);
		cin>>c; c=' '+c;
		sort(a+1,a+1+m);
		sort(c.begin(),c.end()); int l=1;
		for(int i=1;i<=m;i++)
		{
			if(vs[a[i]]) continue;
			s[a[i]]=c[l++]; vs[a[i]]=1;
		}
		for(int i=1;i<=n;i++) printf("%c",s[i]);
		puts("");
	} 
	return 0;
}

T4 Mathematical Problem

题意

给一个长度为 n 的由 09 数字组成的字符串,你可以在数字之间插入 n2×+,得到一个有效的运算式。

注意 09 是合法的,并被看作 9。例如 +9×8×70+09(符号只能放在数字中间)、98×70+0+9(必须恰好有 4 个符号)是非法的。

运算式的结果是根据数学规则计算的——首先进行所有乘法运算,然后进行加法运算。请你找到最小的结果。

解析

赛时唐氏,一眼数据范围然后开始区间 dp,更唐氏的是赛时暴力处理乘积,O(n5) 最后调出来还过了!!!

赛后优化到 O(n4),感觉还挺快的。

n4 code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 25;
int t,n,a[N];
LL f[N][N],ans;
 
int work()
{
	int b[N]; ans=1e9;
	for(int i=1;i<n;i++)
	{
		memset(f,0x3f,sizeof(f));
		int o=1,p=1;
		while(o<=n)
		{
			if(o==i) b[o]=a[p]*10+a[p+1],p+=2;
			else b[o]=a[p++]; o++;
		}
		for(int j=1;j<n;j++) f[j][j]=b[j];
		for(int len=2;len<n;len++)
		{
			for(int l=1,r=l+len-1;r<n;r++,l++)
			{
				LL tmp=1;
				for(int k=l;k<=r;k++)
				{
					tmp*=b[k];
					if(k==r) f[l][r]=min(f[l][r],tmp);
					else f[l][r]=min(f[l][r],tmp+f[k+1][r]);
					if(tmp>ans) break;
				}
			}
		}
		ans=min(ans,f[1][n-1]);
	}
	return ans;
}
 
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n); bool fl=0;
		for(int i=1;i<=n;i++) scanf("%1d",&a[i]),fl|=(!a[i]);
		if(fl&&n>3) puts("0");
		else printf("%d\n",work());
	} 
	return 0;
}

正解是贪心,因为要放 n2 个计算符,所以一定有两个数要拼凑一下。

n=2 特判一下,n>2 时先枚举所有拼凑方案,

对于得到的 n1 个数,如果是 1 直接跳过(可以乘),因为剩下的数都比 1 大,所以加法一定比乘法小,因此贪心策略就是直接加。

注意如果全是 1 结果应为 1

#include<bits/stdc++.h>
using namespace std;
const int N = 21;
int t,n,a[N],b[N];

int work()
{
	int ans=1e9;
	for(int i=1;i<n;i++)
	{
		int res=0;
		for(int j=1,p=1;j<n;j++,p++)
		{
			if(p==i) b[j]=a[p]*10+a[p+1],p++;
			else b[j]=a[p];
		}
		for(int j=1;j<n;j++)
		{
			if(b[j]==0) return 0;
			if(b[j]!=1) res+=b[j];
		}
		res=max(1,res);
		ans=min(ans,res);
	}
	return ans;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%1d",&a[i]);
		if(n==2) printf("%d\n",a[1]*10+a[2]);
		else printf("%d\n",work());
	}
	return 0;
}

T5 Beautiful Array

题意

n 个数字和 k,每次操作可以将任意一个数加 k

现在你可以将这 n 个数任意排列,求让它变成一个回文序列的最小操作次数。

如果不能输出 1

回文序列定义为 bi=bni+1  (1in)

解析

我们按模数分组(需要离散化),如果两个数 mod k 相等,那么他们两个可以通过操作变成相等的数。

因此我们分类后排序,每组相邻的两个数之差 ÷k 就是需要操作数,求和即可。

要求最多有一组个数为奇数,才能满足一一配对,否则不可能满足。

问题在奇数时,因为奇数中间的数不用配对,所以我们在计算时应该删掉一个。

问题就是去掉哪一个数最优,首先,这个数一定是排序后奇数位上的数。

然后我们先假定去掉这一组中的第一个数,计算出一个值。

每一次更改其实就是进行 (v[i+1]v[i])+(v[i]v[i1]),也就是将我们选取的两个点向前挪一位。


变成

因此我们可以 O(n) 处理。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+5;
int t;
int n,k,a[N];
vector<int> v[N];
map<int,int> mp;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		LL ans=0;
		int tot=0;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			int tmp=a[i]%k;
			if(mp.find(tmp)==mp.end()) mp[tmp]=++tot;
			v[mp[tmp]].push_back(a[i]);
		}
		int fl=0;
		for(int i=1;i<=tot;i++)
		{
			sort(v[i].begin(),v[i].end());
			if(v[i].size()&1)
			{
				fl++;
				if(fl==2)
				{
					puts("-1");break;
				}
				LL tmp=0;
				for(int j=2;j<v[i].size();j+=2) tmp+=(v[i][j]-v[i][j-1])/k;
				LL res=tmp;
				for(int j=1;j<v[i].size();j+=2)
				{
					tmp=tmp-(v[i][j+1]-v[i][j])/k+(v[i][j]-v[i][j-1])/k;
					res=min(res,tmp);
				}
				ans+=res;
			}
			else
				for(int j=1;j<v[i].size();j+=2) ans+=(v[i][j]-v[i][j-1])/k;
		}
		if(fl<2) printf("%lld\n",ans);
		for(int i=1;i<=tot;i++) v[i].clear();
		mp.clear();
	}
}

CF 不能用 unordered_map

据 qinyun 悲惨经历,CF 用 unordered_map 真的会被 Hack

unordered_map 实现原理是哈希表,有一个固定的模数。。。

posted @   ppllxx_9G  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示