P8345 「Wdoi-6」华胥之梦
Dr_Gilbert · · 题解
P8345 「Wdoi-6」华胥之梦
UPD 2022-05-20: 修改一处笔误
【题目大意】
给定长度为
接下来给出
【数据范围】
-
- 对于
20\% 的数据,有a_i 全部相同。 - 对于另
20\% 的数据,有a_i 单调递增。
看到这个题意和这个数据范围,感觉没有任何思路,不妨从特殊性质入手先拿部分分。
这个贪心策略的证明,在这里分两部分,第一部分是论证若所走的点一定是点集内的点,则路径长度最短;而第二部分是若走的顺序一定按
对这个式子进行一些变换,就可以得到
对于这条边的反向边
将上式中
显然,
所以如果不需要经过点
由第一部分的结论,最短路径上的点一定都在点集内。且由边权非负,可得所走路径一定是按某个顺序依次连接点集中所有点的一条链。所以对于点集
化简得
可见,最终的路径长度只和路径的起点和终点有关。只需保证起点的
当然,从第二部分的证明可以发现,完全没有必要对集合
当然,这道题时限
代码如下:
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct po{
int val,x;
bool operator <(const po& a)const{
return val<a.val;
}
}p[1000010];
int s[1000010],a[1000010];
bool cmp(int x, int y){return (a[x]<a[y]);}
bool cmp2(po a, po b){return a.x<b.x;}
signed main(){
int n,c,q;
cin>>n>>c>>q;
for (int i=1;i<=n;i++){
cin>>p[i].val;
p[i].x=i;
}
sort(p+1,p+1+n);//排序
for (int i=1;i<=n;i++) a[p[i].x]=i; // 存排名
sort(p+1,p+1+n,cmp2);
while (q--){
int k;cin>>k;
for (int i=1;i<=k;i++) cin>>s[i];
sort(s+1,s+1+k,cmp); // 按a_i从小到大
int ans=0;
for (int i=2;i<=k;i++){
ans+=p[s[i-1]].val-2*p[s[i]].val+c;
}
cout<<ans<<endl;
}
return 0;
}