[CSP-S 2024] 决斗 逐个测试点详解,带你骗分
考场上如果想不到正解,不妨先写其中测试点的答案,一方面是先拿到一些分数,另一方面也可以脱开思路,有助于想到正确的解法。
题目大意
n张卡牌,i卡牌如果大于j卡牌,j被淘汰,i攻击成功,一个卡牌只能攻击一次,使得剩余的卡牌数量最多。
1-4 测试点 20分
\(n\le10\),可以全排列,所有攻击顺序的数量 \(n! =3628800\le 10^7\) ,可以枚举所有攻击顺序,后一张卡牌攻击前一张,找到剩余卡牌最多的方案。
const int N = 1e5+5;
int arr[N];
int n;
int id[N];
int usd[N];
int ans;
void dfs(int a){
if(a == n){
// 递归结束
int res = n;
for(int i=1;i<n;i++){
if(arr[id[i]] > arr[id[i-1]]){
res --;
}
}
if(res < ans){
ans = res;
}
}
for(int i=0;i<n;i++){
if(!usd[i]){
usd[i] = 1;
id[a] = i;
dfs(a+1);
usd[i] = 0;
}
}
}
void solve1(){
ans = n;
dfs(0);
printf("%d\n",ans);
}
int main(){
freopen("duel1.in","r",stdin);
cin>>n;
for(int i=0;i<n;i++){
cin>>arr[i];
}
if(n <= 10){
solve1();
}
return 0;
}
5-10 测试点 30分
由于所有的 \(r\le2\),那么只有一种攻击情况,就是 \(r=2\) 的卡牌战胜 \(r=1\) 的。所以只要统计 \(r=2\) 的数量 \(r_2\),和 \(r=1\) 的数量 \(r_1\) 。
如果 \(r_1\le r_2\) ,那么所有的 \(r_1\) 都会被击败,答案为 \(r_2\)
如果 \(r_1\gt r_2\) ,那么 \(r_2\) 当中全部存活,\(r_1\) 当中会存活下来 \(r_1-r_2\) ,答案为 \(r_1-r_2+r_2=r_1\)
\[存活数=\begin{cases}
r2 &r_1\le r_2 &所有的r_1都被击败了,只剩下r_2\\
r1 &r_1\gt r_2 &r_2击败了一部分r_1,但存活总数不变\\
\end{cases}
\]
const int N = 1e5+5;
int arr[N];
int n;
// 5-10 测试点
void solve2(){
int r1=0,r2=0;
for(int i=0;i<n;i++){
if(arr[i] == 1)r1++;
else r2++;
}
if(r1 <= r2)printf("%d\n",r2);
else printf("%d\n",r1);
}
int main(){
cin>>n;
int maxR = 0;
for(int i=0;i<n;i++){
cin>>arr[i];
if(arr[i] > maxR) maxR = arr[i];
}
if(maxR <= 2){
solve2();
}
return 0;
}
11-15 测试点 20分
这里n只有30个,但所有的r是随机分布在 \(1-10^5\),那么也就说明几乎所有的r都不相同,那直接输出1就可以了,只有最大的一个会存活下来,其他的都会被淘汰。
这应该是最简单的20分了,代码量也极少,只需要用一个set来判断是否有重复的情况即可。
const int N = 1e5+5;
int arr[N];
int n;
// 11-15测试点
void solve3(){
printf("%d\n",1);
}
int main(){
cin>>n;
set<int> se;
bool all_one = true;
for(int i=0;i<n;i++){
cin>>arr[i];
if(se.find(arr[i]) != se.end()){
all_one = false;
}
se.insert(arr[i]);
}
if(all_one){
solve3();
}
return 0;
}
16-20 测试点 30分
首先将所有卡牌进行从小到大排序,每次处理一批数值相同的卡牌,当前正在处理的卡牌一定比处理过的卡牌数值大。那这和 \(r\le2\) 的情况就很类似了。处理过的卡牌我们看作是r=1的卡牌,正在处理的卡牌,我们看作是r=2的卡牌。情况也是类似的
\[存活数=\begin{cases}
r2 &r_1\le r_2 &所有处理过的卡牌r_1都被击败了,只剩下当前正在处理的r_2\\
r1 &r_1\gt r_2 &当前的卡牌r_2击败了一部分处理过的r_1,但存活总数不变\\
\end{cases}
\]
复杂的思路可以由简单的思路拓展而来,这里也体现出来了我们从小的测试点入手的好处,可以给我们提供思路,帮助我们解题。
const int N = 1e5+5;
int arr[N];
int n;
void solve4(){
sort(arr,arr+n);
int r1 = 0,r2 = 0,max;
for(int i=0;i<=n;i++){
if(i == 0 || i == n || arr[i] > max){
if(r1 <= r2) r1 = r2;
max = arr[i];
r2=0;
}
r2++;
}
printf("%d\n",r1);
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>arr[i];
}
solve4();
return 0;
}

浙公网安备 33010602011771号