10.25集训解题报告

T1 方(\(square\)

题面:

上帝说: “要有方”。
ZAY说: “要有六方”。
二人争论不休,于是ZAY想要建立一个六方世界,来证明六方才是人间正道。
ZAY的六方世界是这样的
上帝说: “要有方”。
ZAY说: “要有六方”。
二人争论不休,于是ZAY想要建立一个六方世界,来证明六方才是人间正道。
ZAY的六方世界是这样的

在富饶的ZAY王国一共居住着N户家庭,每家每户都生活在一个六边形的方块中,由于ZAY想让王国
里的人互相交流,所以N户家庭形成一个连通块。为了防止非法移民,ZAY决定用一堵墙将所有的家庭围
起来。
ZAY制定了如下规则

  1. 墙在方块里
  2. 墙不能在家庭里
  3. 任何家庭不能在墙外
  4. 墙内可以有空白方块
    定义围墙长度为所占方块数,请你设计家庭以及围墙方案,使得围墙总长最短。

思路:

找规律,一层一层向外拓展, 贡献每隔 \(n\) 个 变一次,特殊的,每一圈的第一个一定变,最后一个一定不变。
然后模拟即可。

代码:

ll n;
ll ans; 
ll sum=6;
ll wz=1;
ll js=1;
int sta[10];
int Ans[7]={0,6,8,9,10,11,12};
int main(){
	n=read();
	if(n<=6) {cout<<Ans[n]; return 0;}
	while(wz+sum<=n) {
		wz+=sum; sum+=6; ++js;
	}
	sta[0]=wz;
	for(int i=1; i<=6; ++i) {
		sta[i]=wz+i*(sum/6);
	}
	int k=lower_bound(sta, sta+7, n)-sta;
	ans=sum+k;
	if(sta[k]!=n) ans--;
	if(wz<n) ans++;
	cout<<ans;
}

T2 肥宅快乐机(\(dundundun\)

题面:

售货机里一共有 \(n\) 个物品,每个物品 \(a_i\) 个,自然 还有 \(n\) 个购买按钮。

正常情况下,按下第 \(i\) 个按钮,需要支付 \(c_i\) 的钱,然后就会跳出一个物品 \(i\)。如果这个物品卖完了,按下按钮无效。

但是这台售货机的电路连接出了问题,第 \(i\) 个按钮的弹出电路连向了物品 \(f_i\)

假设按下了第 \(i\) 个按钮,售货机的执行逻辑如下:

  1. 判断第 \(i\) 个物品是否为空。
  2. 如果是,不执行任何操作,退出购买程序。
  3. 否则要求支付 \(c_i\) 的钱。
  4. 因为电路坏了,实际会弹出物品 \(f_i\)

ZAY凭借高超的运算能力计算出来 \(f_i\) 的值,并且上网查询了每种物品的卖出价格 \(d_i\),ZAY有无限本金,机制的他想通过买入和卖出最大化得到的钱。

思路:

一堆基环树。
不难发现,直接连贡献最大的边,最后整张图只有链和环。
如果是链,除了叶子都有贡献。
如果是环,那么断掉贡献最小的,还有就是次大值也会产生贡献。

代码:

struct node {
	ll f, c, d, a;
}sz[100005];
int n;
int t[100005];
int t2[100005];
ll ans;
bool pd[100005];
void slove(int x) {
	int v=t[x];
	ll S=sz[x].d-sz[v].c;
	if(v==x) {
		ans+=S;
		return ;
	}
	ll maxx=-1e18;
	if(t2[x])
	maxx=sz[t[x]].c-sz[t2[x]].c;
	maxx=max(maxx, -S);
	while(pd[v]==0&&t[v]) {
		pd[v]=1;
		S+=sz[v].d-sz[t[v]].c;
		if(t2[v])
		maxx=max(maxx, sz[t[v]].c-sz[t2[v]].c);
		maxx=max(maxx, sz[t[v]].c-sz[v].d);
		v=t[v];
	}
	if(v!=x) ans+=S;
	else ans+=S+maxx;
}
int main(){
	n=read();
	for(int i=1; i<=n; ++i) {
		sz[i].f=read(); sz[i].c=read(); sz[i].d=read(); sz[i].a=read();
	}
	for(int i=1; i<=n; ++i) {
		if(sz[i].c>=sz[sz[i].f].d) continue ;
		if(t[sz[i].f]==0) t[sz[i].f]=i;
		else {
			if(sz[i].c<sz[t[sz[i].f]].c) {
				t2[sz[i].f]=t[sz[i].f];
				t[sz[i].f]=i;
			}
			else if(t2[sz[i].f]==0||sz[i].c<sz[t2[sz[i].f]].c) {
				t2[sz[i].f]=i;
			}
		}
	}
	for(int i=1; i<=n; ++i) {
		if(t[i]==0) continue ;
		ans+=1LL*(sz[i].a-1)*(sz[i].d-sz[t[i]].c);
	}
	for(int i=1; i<=n; ++i) {
		if(t[i]==0) continue ;
		if(pd[i]) continue ;
		pd[i]=1;
		slove(i);
	}
}

T3 油炸字符串(\(string\)

题面:

ZAY赚到了大笔钱,于是想去买吃的。

字符是一种生活在草原上的优雅生物,其肉炸来鲜美无比。

于是ZAY想吃油炸字符串,但是由于串串子太难了,他遇到了麻烦。

ZAY串字符串的过程是这样的,初始时他拥有一种基础字符串 \(p\) 和一个空签子 \(S\),每次他可以选择签子的任何一个位置(最前最后都行)来插入一个 \(p\),一直不停地插直到字符串足够长。

但是悲剧的是,串完后ZAY不记得 \(p\) 长什么样了,现在给你最后的 \(S\),希望你能够还原出最初的 \(p\)

如果有多个 \(p\) 符合要求,选择最短的。

如果有多个 \(p\) 最短,选择字典序最小的。

思路:

区间 dp。

T4 青岛地铁(\(subway\)

题面:

青岛地铁有 \(N\) 地铁站,这些地铁站从 \(1\)\(N\) 编号,有 \(M\) 条地铁连接各个地铁站,这些地铁从 \(1\)\(M\) 编号。第 \(i\) 条地铁是一条连接第 \(A_i\) 个和第 \(B_i\) 个地铁站的双向边,长度为 \(D_i\)。任意两个地铁站间一定有地铁(直接或间接)连接。

修缮计划如下:首先,选择一个自然数 \(X\),将和第一个地铁站距离等于 \(X\) 或在 \(X\) 以下的所有地铁站(含第一个地铁站)相互之间连接一条地下通道。地铁站 \(i\) 和地铁站 \(j\) 之间的距离指,从地铁站 \(i\) 到地铁站 \(j\) 经过的地铁的长度总和的最小值。定义 \(C\) 为一个与修筑地下通道花费有关的量(\(C\) 是整数)。
修筑所有地下通道的花费为 \(C\times X\)

接下来,撤去已经通过地下通道连接的地铁站之间的地铁。撤去地铁的花费不计。

最后,将没有被撤去的地铁进行修补,长为 \(d\) 的地铁修补的花费为 \(d\)

修缮计划实施之前,青岛地铁没有地下通道。请求出青岛地铁修缮花费总和的最小值。

思路:

直接 \(Dij\)
先求出总的 \(d\) 的花费,也就是 \(X=0\) 时的花费。
然后把距离从小到大排序,枚举 \(X\)
\(X\) 在变大,连通块内的点不会减少,只能是一个个加进来。
然后删掉往联通块内新加的边的贡献就行了。
最后对所有 \(X\) 的答案取一个最小值。

代码:

struct edge {
	int t, n; ll d;
}e[400005];
int head[100005], head_size;
void ADD(int f, int t, ll d) {
	e[++head_size]=(edge) {t, head[f], d};
	head[f]=head_size;
}
int n, m, u, v; ll C, d;
ll dis[100005];
struct node {
	int v; ll diss;
	bool operator < (const node &a) const {
		return a.diss<diss;
	}
};
int sz[100005];
bool cmp(int a, int b) {
	return dis[a]<dis[b];
}
void Dij() {
	memset(dis, 0x3f, sizeof(dis));
	dis[1]=0;
	priority_queue<node>q;
	q.push((node){1, 0});
	while(q.size()) {
		node op=q.top(); q.pop();
		if(dis[op.v]!=op.diss) continue ;
		for(int i=head[op.v]; i; i=e[i].n) {
			if(dis[e[i].t]>dis[op.v]+e[i].d) {
				dis[e[i].t]=dis[op.v]+e[i].d;
				q.push((node){e[i].t, dis[e[i].t]});
			}
		}
	}
}
bool pd[100005];
ll ans;
ll S;
int main(){
	n=read(); m=read(); C=read();
	for(int i=1; i<=m; ++i) {
		u=read(); v=read(); d=read();
		ADD(u, v, d); ADD(v, u, d);
		ans+=d; S+=d;
	}
	Dij();
	for(int i=1; i<=n; ++i) {
		sz[i]=i;
	} sort(sz+1, sz+n+1, cmp);
	for(int i=1; i<=n; ++i) {
		for(int j=head[sz[i]]; j; j=e[j].n) {
			if(pd[e[j].t]) S-=e[j].d;
		}
		ans=min(ans, S+C*dis[sz[i]]);
		pd[sz[i]]=1;
	}
	cout<<ans;
}
posted @ 2022-10-26 10:58  Konnya_ku  阅读(36)  评论(2编辑  收藏  举报