专栏文章

题解:P11639 Line Game

P11639题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqbpkvk
此快照首次捕获于
2025/12/04 02:11
3 个月前
此快照最后确认于
2025/12/04 02:11
3 个月前
查看原文

题目链接:P11639 Line Game

个人见解:

这道题的难度我估摸着有 50%50\% 来自题面理解。毕竟这道题无论是从代码还是思维来讲都不像绿的难度。当然只是个人意见,不作参考。

进入正题:

既然题目难理解,那就先从题目下手。

题目大意:

在一个长度为 m+1m+1 的坐标轴上,你从坐标 11 开始,要进行多次操作。
操作内容是给出一些元素,你要删除他们。
删除有两种情况,分别为全部删除部分删除
删除元素遵循以下操作:
  1. 选定一个值域 [L,R][L,R],在这个值域内的所有元素被删除,并付出相应代价,大小为 RL+1R-L+1
  2. 若没有全部删除,则你的坐标 +1+1,你要在到达 m+2m+2 (即出界)之前删除所有元素。
最后输出最小代价和。

题目简化:

多次给出一些元素,全部删除或部分删除,删除付出被删除元素的极差的代价,只能进行 mm部分删除。求出删除所有元素的最小代价和。

题目分析:

题目中要求代价和最小,那么我们要尽可能的使代价被充分利用。因为代价与值域有关,而值域又与元素分布有关,我们要让元素分布集中,最好的方法就是将不集中的元素分成多个集中的部分,也就是部分删除。
因为部分删除只能使用 mm 次,所以要尽可能减少不被利用的值域的长度。那我们可以用一个数组 ee 来记录下给出的元素,排序后二次处理求差,再开一个 resres 数组记录下来,这个过程就是计算出所有不被利用的值域。用 vector 记录方便又适合,是不二之选。
CPP
	vector<int> e;//记录每一条线段的元素 
	vector<int> res;//记录每条线段上相邻元素的差值 
计算答案可以使用整体减空白思想。即用每一组元素的极差之和(代码中最开始记为 ansans),减去被去除的值域的长度,最后得到答案。
代价和最小代价和最小     \iff 去除的值域长度最大去除的值域长度最大
这是显而易见的,为了达到这一目的,我们要对 resres 数组进行降序排序,将前 mm 个(或者不达 mm 个,选择全部差值),全部删除。用代码写就是:
CPP
	For(i,0,res.size()-1){
		if(i>=m-1||res[i]<=0) break;
		ans-=res[i]; 
	}

注意事项:

在计算极差和值域长度时存在是否 +1+1 的常规细节,读者要仔细斟酌。

Code呈现:

CPP
#include<bits/stdc++.h>
//万能头YYDS 
using namespace std;
namespace LKSN{
    template <typename T>
    inline void read(T &x){
       x=0; T f=1;char ch;
       while(!isdigit(ch=getchar())) f-=(ch=='-')<<1;
       while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
       x*=f;
    }
    template <typename T, typename ...L>
    inline void read(T &x,L &...y){
        read(x);
        read(y...);
    }
    template <typename T>
    inline void write(T x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    template <typename T, typename ...L>
    inline void write(T &x,L &...y){
        write(x),putchar(' ');
        write(y...);
    }
}//快读快写 
using namespace LKSN; 
#define ll long long
#define rint register int
#define For(i,a,b) for(rint i=a;i<=b;i++)
#define foR(i,a,b) for(rint i=a;i>=b;i--)
#define FOr(i,a,b,c) for(rint i=a;i<=b;i+=c)
#define fOR(i,a,b,c) for(rint i=a;i>=b;i-=c)
//宏定义 
int n,m;//题目上有,不过多赘述 
ll ans;//记录答案,记得开longlong
vector<int> e;//记录每一条线段的元素 
vector<int> res;//记录每条线段上相邻元素的差值 
bool cmp(int a,int b){return a>b;}//降序排列 
int main(){
    read(n,m);//读入 
    rint a,b;
	For(i,1,n){
		read(a);//读入线段长度 
		e.clear();//记得清空先前线段 
		For(j,1,a){
			read(b);//读入线段元素 
			e.push_back(b);//压入动态数组(是叫动态数组吧) 
		}
		sort(e.begin(),e.end());//给元素排序
		For(i,1,a-1){
			res.push_back(e[i]-e[i-1]-1);//解题关键!!! 
		}
		ans+=e[a-1]-e[0]+1;//计算整体极差 
	}
	sort(res.begin(),res.end(),cmp);//降序排序 
	For(i,0,res.size()-1){
		if(i>=m-1||res[i]<=0) break;//超出允许次数或无法再删就跳出 
		ans-=res[i];//对应上面整体减空白 
	}
	write(ans);//输出答案 
    return 0;
}
//over~~
最后注明几点:

1. he码的 oier 不是好 oier。

2. 鄙人第一次写题解,不喜勿喷。

3. 如有 hack 数据或内容有误,欢迎指出。


结尾鸣谢:
感谢 K_J_M 大佬和 co7ahang 大佬抽出他们宝贵的时间帮我微调。

评论

0 条评论,欢迎与作者交流。

正在加载评论...