$("head").append('')

P9087 「SvR-2」音符

P9087 「SvR-2」音符

题目传送门

题目描述

本题中「子串」指:

若字符串 \(s\) 中有一段连续的字符构成字符串 \(p\),则 \(p\)\(s\) 的子串。

我们用一个字符串代替一份乐谱,用字符代替每一个音符。

我们定义「重音」表示乐谱中出现了两个连续的相同字符,如 \(\tt eeeee\) 中存在 \(4\) 个「重音」。

现在 Sept 准备写一份长度为 \(n\) 的乐谱给 Tpes 看,他对乐谱的评价标准如下:

  • 乐谱中每出现一个「重音」,他的愤怒值就会增加 \(a\)
  • 乐谱中每有一段长度为 \(k\)子串中不存在「重音」,他的愤怒值就会增加 \(b\)

现在已知 \(n,k,a,b\),请你帮 Sept 构造出一份乐谱,使得 Tpes 的愤怒值 \(x\) 最小

输入格式

本题有多组数据。

第一行一个整数 \(T\),表示数据组数。

接下来 \(T\) 行,每行两个整数 \(n,k,a,b\),意义如题目所述。

输出格式

\(2 \cdot T\) 行,对于每组数据都输出两行:

  • 第 1 行表示 Tpes 最小的愤怒值 \(x\)
  • 第 2 行表示你构造出的乐谱。

输入输出样例 #1

输入 #1

2
4 5 2 2
8 6 3 2

输出 #1

0
Sept
3
2023yyds

说明/提示

数据规模与约定

本题采用捆绑测试。

\(\bf{Subtask}\) \(\bm{n\le}\) \(\bm{\sum n\le}\) \(\bm{T\le}\) \(\bf{Score}\)
\(\sf 1\) \(6\) \(10\) \(3\) \(\tt 10\)
\(\sf 2\) \(10^3\) \(2\times 10^3\) 无特殊限制 \(\tt 30\)
\(\sf 3\) 无特殊限制 无特殊限制 无特殊限制 \(\tt 60\)

对于 \(100\%\) 的数据,有 \(2\le T\le 100\)\(2\le n,k\le 10^5\)\(1\le a,b\le 10^9\)。单组数据内保证 \(\sum n\le 2\times 10^5\)

输出注意事项

输出 \(x\) 和构造乐谱可以看作是两个子问题,如果你只会完成其中的一个,请在另一个子问题对应的地方用符合要求的字符或数字占位。

乐谱中你可以输出任意字符,包括数字、大小写字母等,但不能出现空格

Special Judge 返回信息说明

本题采用 Special Judge 判断你的答案是否正确。

checker.cpp 将会以 \(\texttt{Score=}\text A,\texttt{Type=}\text B\) 的方式返回信息。

\(\tt Score\) 类表示你的得分情况,\(\text A\) 有以下取值:

  • \(\text A=1\),表示含义如下:
    \(\text{Accepted.} \texttt{ Your Ans and SM are both proper.}\)
    代表 \(T\) 组答案全部符合要求。
  • \(\text A=2\),表示含义如下:
    \(\text{Partially Correct.}\texttt{ All Ans are right.}\)
    表示该测试点中你的回答中 \(x\) 全部正确,你能得到该测试点 \(20\%\) 的分数。
  • \(\text A=3\),表示含义如下:
    \(\text{Partially Correct.}\texttt{ You pass 70\% tests!}\)
    表示该测试点中你的回答正确的组数不少于\(\lfloor0.7\times T\rfloor\)\(x\) 与乐谱均符合要求),你能得到该测试点 \(10\%\) 的分数。
  • \(\text A=4\),表示该测试点你只能拿到 \(0\) 分。

\(\tt Type\) 类表示你的得分情况,\(\text B\) 有以下取值:

  • \(\text B=0\),表示你的答案全部正确,与 \(\text A=1\) 配对。
  • \(\text B=1\),表示含义如下:
    \(\text{Wrong Answer.}\texttt{ The length of your SM is not right!}\)
    代表你在一组数据中构造的乐谱的长度不为 \(n\)
  • \(\text B=2\),表示含义如下:
    \(\text{Wrong Answer.}\texttt{ Your Ans is not right!}\)
    代表你在一组数据中 \(x\) 的值错误。
  • \(\text B=3\),表示含义如下:
    \(\text{Wrong Answer.}\texttt{ Your Ans and SM are not matched!}\)
    代表你在一组数据中构造的乐谱使 Tpes 产生的愤怒值不为 \(x\)

这里 \(\text{Ans, SM}\) 分别表示 Answer(\(x\) 的值)和 Sheet Music(乐谱)。

注意到 \(\tt Type\) 只会反映你在该测试点中第一次错误的类型。


题解:

读到题的时候还以为是teto那个重音

题意

对于一个长度为 \(n\) 的字符串 \(p\),当有相邻的两个字符相同,即 \(p_i=p_{i+1}\) 时,则让愤怒值增加 \(a\);当连续 \(k\) 个字符没有相邻且相同的字符,即在 \([p_i,p_{i+k}]\) 中,不存在 \(p_i=p_{i+1}\) 时,则让愤怒值增加 \(b\)
请你求出如何构造这个串,使得愤怒值最小。

思路

先考虑贪心,如果对于一个没有特殊性质的串,怎样可以尽可能让成本更小:

  • 如果 \(a\) 远远小于 \(b\),我们不妨在每个子段长度即将达到 \(k\) 的时候加入一个重音,这样就可以维护最少的重音个数。
  • 如果 \(a\) 远远大于 \(b\),那么就抛弃重音吧!

实现

有了大致的思路,就可以开始着手构造了!
首先考虑一下特殊的情况:

  • 对于 \(k>n\) 的情况,永远不会出现愤怒值增加 \(b\) 的情况,此时我们只需要考虑尽可能减少重音,那么构造一个相邻字符全都不相同的串就可以了:
if(k>n){
	cout<<"0\n";//别忘了输出代价!
	for(int i=1;i<=n;i++){
		if(i&1)putchar('1');
		else putchar('0');
	}
	cout<<"\n";
	continue;
}

在分析一般情况之前,我们需要想一下怎样达到上文中维护最少的重音个数的效果:我们肯定要保证不存在情况 \(b\) 的同时尽可能让每个重音间隔的更远,也就是说每个重音的距离应该为 \(k-1\)。但是这里要注意一个重音在原串的长度为二。

  • 如果有重音 TA 就会很愤怒,即 \(b\times(k-1)\le a\),这就意味着对于任意的重音,无论它出现在哪里,都会让愤怒值增加。此时我们同样只需要构造一个相邻字符全都不同的串就可以了,此时代价为 \(b\times(n-k+1)\)
if(b*(k-1)<=a){
	cout<<(long long)b*(n-k+1)<<"\n";
	for(int i=1;i<=n;i++){
		if(i&1)putchar('1');
		else putchar('0');
	}
	cout<<"\n";
	continue;
}
  • 剩下的最后一种情况,要保证每一段长度为 \(k\) 的子串里面都存在一个 \(a\)

当这个子段在开头的时候,只需要在右端点 \([k-2,k]\) 这里放入一个重音就可以维护 \([1,2k-2]\) 的相邻不相同串。
那为什么是 \(2k-2\) 这么一个并不美丽的数呢?因为他的后面一个数 \(2k-1\) 作为右端点时,会把原本的重音 \([k-2,k]\) 切开,使其不再构成重音。
因此,在处理中间段的时候,我们需要将串长视为 \(k-1\),即上一段的重音被切开了,占用了此段的一个位置。同时重音还会占据两个位置,也就是说我们维护的相邻不相同串长度将变成 \(k-3\)

else{
	for(int i=1;i<=n;i++){
		if(i%3==1)s[i]=5;
		else if(i%3==2)s[i]=1;
		else s[i]=4;
	}

关于最后一段,我们需要看看它给出一个重音来维护更优还是保留最后的长串更优。

	long long q=((n-1)/(k-1)); // 重音数
	long long c=n-q*(k-1);
	long long lst=b*c;
	if(lst<=a){ // 尾段处理
		cout<<((q-1)*a+lst)<<"\n";
		for(int i=k,j=1;j<q;i+=k-1,j++)s[i]=s[i-1];
	}
	else{
		cout<<q*a<<"\n";
		for(int i=k,j=1;j<=q;i+=k-1,j++)s[i]=s[i-1];
	}
	for(int i=1;i<=n;i++)cout<<s[i];cout<<"\n";
}

AC 代码

#include<bits/stdc++.h>
using namespace std;
long long n,k,t,a,b;
int s[200005];
int main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n>>k>>a>>b;
		if(k>n){
			cout<<"0\n";
			for(int i=1;i<=n;i++){
				if(i&1)putchar('1');
				else putchar('0');
			}
			cout<<"\n";
			continue;
		}
		if(b*(k-1)<=a){
			cout<<(long long)b*(n-k+1)<<"\n";
			for(int i=1;i<=n;i++){
				if(i&1)putchar('1');
				else putchar('0');
			}
			cout<<"\n";
			continue;
		}
		
		for(int i=1;i<=n;i++){
			if(i%3==1)s[i]=5;
			else if(i%3==2)s[i]=1;
			else s[i]=4;
		}
		long long q=((n-1)/(k-1));
		long long c=n-q*(k-1);
		long long lst=b*c;
		if(lst<=a){
			cout<<((q-1)*a+lst)<<"\n";
			for(int i=k,j=1;j<q;i+=k-1,j++)s[i]=s[i-1];
		}
		else{
			cout<<q*a<<"\n";
			for(int i=k,j=1;j<=q;i+=k-1,j++)s[i]=s[i-1];
		}
		for(int i=1;i<=n;i++)cout<<s[i];cout<<"\n";	
	}
	return 0; // 好习惯
}

posted @ 2025-10-12 15:35  lain_yc  阅读(10)  评论(0)    收藏  举报
$("head").append('')