10.30多校聯訓
阿新 • • 發佈:2021-10-30
T1 刪數遊戲
Sol
直接全部數字加起來減一然後除以9就可以了,非常好證正確性。
Code
懶得粘。
T2 格點迷蹤
Sol
構造題。首先考慮直徑最小的構造方案:先看\(n,m\)中有至少一個為奇數:取出奇數那一維的中軸線,然後線上每個點向兩邊一直延伸即可。
每次延長直徑就把邊上的延伸線撇過來。
按照這個邏輯不斷撇就可以了。
如果\(n,m\)均為偶數,要注意無法實現直徑為對角線曼哈頓距離,要特判。
Code
\(Tell\ is\ easy,\ however\ I\ can't\ show\ you\ the\ code.\ Cause\ it's\ too\ hard\ for\ me\ to\ write\ that.\)
T3 沙漠綠洲
Sol
首先可以證明:每一條邊最多隻走一次。那麼其實就是花費\(dis(u,v)\)把\(u,v\)聯通起來。
最開始我想的是直接列舉點集,然後跑\(kruskal\)計算答案取最值,然後發現\(n=2\)的小資料全過,大樣例死活過不了。
然後就發現可能選出來的點集並不只形成一個最小生成樹,而是一個最小生成森林。所以可以套上一個狀壓DP,把原來計算的答案改成只計算處在樹中的數的最小值。
這樣每種狀態表示對應二進位制位上是否被考慮。設\(g(now)\)表示當前狀態最優答案,\(f(now)\)表示當前狀態全部在同一樹上的答案。那麼答案有
加一個記搜,時間複雜度\(O(2^{2n})\)
Code(不帶優化)
#include<bits/stdc++.h> using namespace std; const int maxn=20; int n; double a[maxn],b[maxn],c[maxn]; double dis[maxn][maxn],rst; bool con[maxn]; int fa[maxn],len,siz[maxn]; double cost[maxn],wat[maxn]; struct edge { int from,to; double v; bool operator<(const edge &x)const { return v<x.v; } }di[maxn*maxn]; inline int findf(int x) { if(fa[x]==x)return x; return fa[x]=findf(fa[x]); } double f[65546],g[65546]; inline void klske() { for(int i=1;i<=n;i++)fa[i]=i,cost[i]=0,wat[i]=c[i],siz[i]=1; int now=1,al=0; for(int i=1;i<=n;i++)if(con[i])al++; if(al<2) { double an=1000000000.0;now=0; for(int i=1;i<=n;i++) { if(con[i]) { now|=(1<<i-1); an=min(an,c[i]); } } f[now]=an; return; } for(int i=1;i<=len;i++) { if(con[di[i].from]==0||con[di[i].to]==0)continue; int x=di[i].from,y=di[i].to; double val=di[i].v; x=findf(x),y=findf(y); if(x==y)continue;now++; fa[x]=y;siz[y]+=siz[x];wat[y]+=wat[x];cost[y]+=cost[x]+val; if(now==al)break; } double an=1000000000.0,an1=1000000000.0; now=0; for(int i=1;i<=n;i++) { if(!con[i])continue; now|=(1<<i-1); if(fa[i]==i)an=min(an,(wat[i]-cost[i])/(siz[i])); an1=min(an1,c[i]); } f[now]=max(an,an1); return; } inline void dfs(int step) { if(step==n+1) { klske(); return; } con[step]=1;dfs(step+1); con[step]=0;dfs(step+1); return; } inline double getans(int zt) { if(g[zt]>=0)return g[zt]; g[zt]=f[zt]; for(int i=1;i<=zt;i++) { if(i==zt)break; if((i&zt)==i)g[zt]=max(g[zt],min(getans(i),getans(i^zt))); } return g[zt]; } signed main() { freopen("desert.in","r",stdin); freopen("desert.out","w",stdout); scanf("%d",&n); memset(g,-1,sizeof(g)); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&a[i],&b[i],&c[i]); } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { dis[i][j]=sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])); } } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++)di[++len]=(edge){i,j,dis[i][j]}; } sort(di+1,di+len+1); dfs(1); getans((1<<n)-1); printf("%.10lf\n",g[(1<<n)-1]); return 0; }
T4 奇異函式
不會。