ABC 422 E-G题解
E - Colinear
想到了随机枚举命中率很高,没想到真让我分析概率,开眼界了()
题目要求询问是否存在一条直线能够穿过一半所给出的点,对于任意两个点组成的一条直线,若这条直线符合要求,则选取到这两个点的概率为:
所以随机选取两点,该直线不是答案的概率差不多 \(\frac{3}{4}\),对答案的判断可以 \(O(n)\) 解决,所以我们随机选 \(T\) 次 失败率不会大于 \((\frac{3}{4})^{T}\) 多跑几组也能行。
点击查看代码
const int N=5e5+5;
int n,x[N],y[N];
int T=200;
void xpigeon(){
rd(n);
for(int i=1;i<=n;i++){
rd(x[i],y[i]);
}
mt19937_64 rnd(time(0));
for(int t=1;t<=T;t++){
int i,j;
do{
i=rnd()%n+1,j=rnd()%n+1;
}while(i==j);
int a=y[i]-y[j];
int b=x[j]-x[i];
int c=x[i]*y[j]-x[j]*y[i];
int tmp=0;
for(int k=1;k<=n;k++) tmp+=(a*x[k]+b*y[k]+c==0);
if(tmp*2>n){
cout<<"Yes\n";
cout<<a<<" "<<b<<" "<<c<<"\n";
return ;
}
}
cout<<"No\n"<<'\n';
}
F - Eat and Ride
以为秒了,结果还是我唐啊()
这种转化是怎么想到的....
好吧后来根据_kenma_的教学了解到,思路方向是:题意原有的贡献是无法直接计算的,想要求最短路还是要把贡献拆到每个点上变成可计算的形式。
给的图是一个无向图,所以很多方法都受到了限制,我们重新考虑 “体重” 带来的贡献,对于每一个终点 \(i\) ,我们把一路上“体重”的持续贡献拆到刚增加这一部分“体重”时的单点上,于是重新表述本题问题:
高桥开始了一次旅行,他有几张车票。
如果他有 \(n\) 张车票,那么每当他到达顶点 \(v\) 时,就会消耗 \(nW_v\) 单位的燃料。
每当他经过一条边时,他会释放一张门票。
通过适当地确定他的初始门票数量和路径,使他从到达顶点 \(1\) 到顶点 \(i\) 所消耗的燃料最小。
设一个点 \((u,n)\) 表示在点 \(v\) 时,可能的剩余车票数为 \(n\),其可以向所有可到达的 \((v,n-1)\) 连一条 \(nW_v\) 的边,根据这个标准建图跑 \(dij\) 即可解决本题,答案是 \((1,n)\) 到 \((i,0)\) 的最短距离。
时间复杂度是 \(O((nm+n^2) \log {n})\) 其实有点难过,我们考虑一个更优一点的写法。
考虑设计状态 \(dp_{u,k}\) 表示到达点 \(u\) 还剩 \(k\) 张票的最小代价,转移只需要枚举出边到达点 \(v\) 并将车票减一再取 \(min\) 即可,最终车票为 \(0\) 时,每个点的 \(dp\) 值一定取到最小代价,因为可以将这个过程看作有向无环图的形式,故答案肯定是从最优的路径上一步步取得的。
时间复杂度来到 \(O(nm)\) 。
点击查看代码
const int inf=1e18;
int dp[5005][5005];
int n,m,w[5005];
vector<int> e[5005];
void xpigeon(){
rd(n,m);
for(int i=1;i<=n;i++){
rd(w[i]);
}
for(int i=1,a,b;i<=m;i++){
rd(a,b);
e[a].pb(b);
e[b].pb(a);
}
for(int i=2;i<=n;i++) dp[i][m]=1e18;
for(int i=m;i;i--){
for(int j=1;j<=n;j++) dp[j][i-1]=1e18;
dp[1][i]=0;
for(int j=1;j<=n;j++) dp[j][i]+=w[j]*i;
for(int j=1;j<=n;j++){
for(auto y:e[j]){
dp[y][i-1]=min(dp[y][i-1],dp[j][i]);
}
}
}
dp[1][0]=0;
for(int i=1;i<=n;i++) cout<<dp[i][0]<<'\n';
}
G - Balls and Boxes
官方题解太神秘,差点没敢改,卷积咋做我也不会,但是我学到了 link 的根号分治做法。
我操根号咋这么牛逼
第一问
球是相同的,可以直接 \(dp\)
考虑 \(dp\) 状态 \(f(i,j)\) 表示前 \(i\) 个盒子里共放了 \(j\) 个球的方案数。
\(O(n)\) 就能做。
第二问
相当于求:
我们可以给出两种做法:
- 直接枚举 \(x,y\) 再得到 \(z\) 最后直接算贡献,时间复杂度 \(O(\frac{n^2}{ab})\)
- 可以先固定前两个盒子的分配方案数,这样可以用一个 \(dp\) 来做,设 \(f(i,x,y)\) 表示前 \(i\) 个球分配到两个盒子中,在模 \(a,b\) 的情况下分别等于 \(x,y\) 时的方案数,转移时考虑下一个球可以选择放到两者其中一个盒子里。最后再单独枚举放进第三个盒子里多少个,每次的贡献是 \(\binom{n}{cz} \cdot f(n-cz,0,0)\)。时间复杂度 \(O(nab)\)。
考虑根号分治,当 \(ab \geq \sqrt n\) 用做法 \(1\),否则用做法 \(2\) ,时间复杂度变为 \(O(n \sqrt n)\)。

浙公网安备 33010602011771号