The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)

原题链接:Dashboard - The 2022 ICPC Asia Xian Regional Contest - Codeforces

目录

 J. Strange Sum

 F. Hotel

 C. Clone Ranran

 G. Perfect Word

 E. Find Maximum

 L. Tree 


 J. Strange Sum

题意:The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第1张图片思路:当我们选择i=n时,我们则可以选择整个区间,所以我们在这个区间内我们可以分别选择最大的2个元素、最大的1个元素、不选,三者取max即可。

代码:

void solve() {
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	cout<

 F. Hotel

题意:The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第2张图片

The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第3张图片思路:对于每个队伍我们进行分治,当队伍中的队员性别都不同的时候,ta们需要住三间房间,总共有两种情况:三人都住单人间,或者三人都住双人间(双人间只住一个人)。当队伍中存在相同性别的队员时,也是只有两种情况:两人一起住双人间,一人住单人间;两人一起住双人间,一人住双人间。每种情况取min然后累加即可。

void solve() {
	int n,a,b,ans=0;
	cin>>n>>a>>b;
	for(int i=1; i<=n; i++) {
		mapmp;
		int now=min(3*a,3*b);
		cin>>s;
		for(int j=0; j<=2; j++) {
			mp[s[j]]++;
			if(mp[s[j]]==2)now=min(min(now,a+b),2*b);
		}
		ans+=now;
	}
	cout<

 C. Clone Ranran

 题意:The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第4张图片

思路:若要进行克隆操作的话,肯定是克隆完然后再一起答题是最优的。所以我们枚举克隆次数,答案取min即可。每次枚举的答案为克隆次数+(问题数)/(克隆后的数量)<-(向上取整)。因为它的复杂度是log级别的,所以不会超时。 

代码:

void solve() {
	int a,b,c,ans=1e18;
	cin>>a>>b>>c;
	for(int i=0; i<=34; i++) {
		int sum=a*i;
		sum+=b*((c+f[i]-1)/f[i]);
		ans=min(ans,sum);
	}
	cout<>_;
	while(_--)
		solve();
}

G. Perfect Word

题意:The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第5张图片

思路:若一个单词S满足条件,则它的子串S[1~n-1]和S[2~n]也满足条件,所以我们根据字符串长度从下往上拼出最长的单词,若这个单词S能在比它长度小的set集合中,找到S[1~n-1]和S[2~n]两个字串,说明这个字符合法,放入set,反之continue。答案在模拟的过程中取max即可。

代码:

bool cmp(string a,string b) {
	return a.size()v;
	sets;
	int n,ans=0;
	cin>>n;
	for(int i=1; i<=n; i++) {
		string x;
		cin>>x;
		v.push_back(x);
	}
	sort(v.begin(),v.end(),cmp);
	for(int i=0; i

 E. Find Maximum

题意: 

思路: 手玩函数(bushi)后可得f(x)表达的是x在三进制下各个位的数之和+三进制长度,所以2是越多越好,我们可以用右边界r来进行贪心。因为已经r是上限了,所以不可能令它三进制的某一位增加,我们对r能进行的操作只有减少它的某一位,然后根据贪心的思想,若它某一位减少了,则该位之后的位都可以变成2,这是因为3^1+3^2+.......+3^(i-1)<3^i,所以就算后面的位都变成2了,也不会超过r的范围,我们需要判的就是变完之后会不会小于l。

总结一下,就是枚举r在三进制上的每一位,然后该位-1,后面的位都变成2,再判断它是否大于l,若合法则答案取min。别忘了把答案的初始值设为f(r)。

代码:

int f(vectorv) {//用来计算三进制转换为10进制后的值 
	reverse(v.begin(),v.end());
	int sum=0,now=1; 
	for(auto x:v) {
		sum+=x*now;
		now*=3;
	}
	return sum;
}
int f2(vectorv) {//用来计算f(x) 
	reverse(v.begin(),v.end());
	while(v.size()&&!v.back())v.pop_back();
	int sum=0;
	for(auto x:v)sum+=(x+1);
	return sum;
}
void solve() {
	vectora;
	int l,r,rr,ans=0;
	cin>>l>>r;
	rr=r;
	while(rr) {
		a.push_back(rr%3),ans+=(rr%3+1);
		rr/=3;
	}//将r转换为三进制存入vector,并且使ans的初始值为f(r) 
	reverse(a.begin(),a.end());
	for(int i=0; ix;
		x=a,x[i]--;
		for(int j=i+1; j=l)ans=max(ans,f2(x));//判断是否合法 
	}
	cout<

L. Tree 

 题意:

The 2022 ICPC Asia Xian Regional Contest(C/E/F/G/J/L)_第6张图片

思路:条件一可以转化为在树内删一条链,条件二可以转化为在树内删叶子节点,所以我们先跑一遍dfs预处理后,枚举删的叶子节点层数,答案取min即可。具体实现见代码注释。 

代码: 

vectore[maxn];
int dep[maxn],dis[maxn],cnt=0;
//dep[i]表示的是i节点到最深叶子节点的距离
//dis[i]表示的是有多少个节点到叶子节点的距离为i
void dfs(int u) {
	dep[u]=1;
	for(auto x:e[u]) {
		dfs(x);
		dep[u]=max(dep[u],dep[x]+1);
	}
	dis[dep[u]]++;
}
void solve() {
	int n;
	cin>>n;
	for(int i=1; i<=n; i++) e[i].clear(),dis[i]=0;
	for(int i=2; i<=n; i++) {
		int x;
		cin>>x;
		e[x].push_back(i);
	}
	dfs(1);
	int ans=dep[1];//初始情况是什么叶子都不删的情况,也就是根节点到叶子节点的距离
	for(int i=1; i<=dep[1]; i++)ans=min(ans,dis[i]+i-1);
	//i表示删了(i-1)层叶子节点,那么剩下的链的个数就是dis[i]
	cout<

你可能感兴趣的:(区域赛题解,算法)