描述
有\(m\)條河,每條河的兩邊有居民點,所以共有\(m+1\)排居名點;
如果要從一排居名點到另一排相鄰的居民點需要過河;
現在有\(n\)個人,每個人的起點座標是\((p_,s_)\),終點\((q_,t_)\);
你可以在每條河上修建一座橋,過河必須通過橋;
相鄰居民點距離為\(1\),不考慮過河的時間;
問\(n\)個人到終點的路徑之和最小是多少;
範圍\(1 \le n , m \le 10^5 \ , \ 1 \le s_ ,t_ \le 10^9 ,\ 1 \le p_,q_ \le m+1\)
題解:\[\begin
f_ &= g_(j) \ \ &(i=1) \\
f_ &= min \ \ + \ b_ |a_-a_| \ + \ g_(j) \} \ \ &(i \gt 1) \\
\end
\]所以得到乙個\(o(n^2m)\)的\(dp\),可以用單調佇列簡單優化到\(o(nm)\);
\(g_\)一定是凸函式,所以\(f_\)一定是凸的,同時由於凸函式對加法封閉,所以直接考慮轉移前半部分:
考慮在\(f_\)上找到兩個斜率為 \(-b_\) 和\(b_\)的點設為\(j1和j2\)
\[f_ = g_(j) +
\begin
&f_ &+& b_ |a_-a_| &(j \lt j1)\\
&f_ &+ &b_ |a_-a_| &(j1 \le j \le j2)\\
&f_ &+ &b_ |a_-a_| &(j2 \lt j)\\
\end
\](分析絕對值簡單比較就可以得到)
所以\(f_ \to f_\)就是區間賦值一次函式,區間加一次函式,所以\(f_\)仍然是凸的;
用線段樹或者\(set\)維護差分即可;
注意要另外維護一下\(f_\) ;
#include#define pb push_back
#define mk make_pair
#define ls (k<<1)
#define rs (k<<1|1)
#define ll long long
#define inf 1e18
#define il inline
using namespace std;
const int n=100010;
int n,m,tot,sub[n<<1],p[n],s[n],q[n],t[n];
vectora[n];
ll b,sum[n],b[n],ans;
il char gc()
il int rd()
ll s[n<<3],d[n<<3],dr[n<<3],ly1[n<<3],ly2[n<<3];
il void build(int k,int l,int r)
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}il void mfy1(int k,int l,int r,ll x)
il void mfy2(int k,int l,int r,ll x)
il void pushup(int k,int l,int r)
il void pushdown(int k,int l,int r)
if(ly1[k])
}void update1(int k,int l,int r,int x,int y,ll v)
int mid=(l+r)>>1;
pushdown(k,l,r);
if(y<=mid)update1(ls,l,mid,x,y,v);
else if(x>mid)update1(rs,mid+1,r,x,y,v);
else update1(ls,l,mid,x,mid,v),update1(rs,mid+1,r,mid+1,y,v);
pushup(k,l,r);
}void update2(int k,int l,int r,int x,int y,ll v)
int mid=(l+r)>>1;
pushdown(k,l,r);
if(y<=mid)update2(ls,l,mid,x,y,v);
else if(x>mid)update2(rs,mid+1,r,x,y,v);
else update2(ls,l,mid,x,mid,v),update2(rs,mid+1,r,mid+1,y,v);
pushup(k,l,r);
}int query1(int k,int l,int r,ll x)
ll query2(int k,int l,int r,int x,int y)
il void update1(int cur)
sub[++tot]=1;
sort(sub+1,sub+tot+1);
tot=unique(sub+1,sub+tot+1)-sub-1;
for(int i=1;i<=n;++i)
a[l+1].pb(s[i]);sum[l+1]+=sub[s[i]]-1;
a[r].pb(t[i]);sum[r]+=sub[t[i]]-1;
b[l+2]++,b[r+1]--;
} build(1,0,tot);
update1(1);
for(int i=2;i<=m;++i)
int pos=query1(1,0,tot,0);
if(pos>1)ans+=query2(1,0,tot,1,pos-1);
printf("%lld\n",ans);
return 0;
}
//這是fxy寫的set;
#pragma gcc optimize(3)
#include#include#include#include#include#include#include#include#define rg register
#define ll long long
#define ldb long double
#define ull unsigned long long
#define view(i,x) for(rg int i=hd[x];i!=-1;i=e[i].nt)
#define go(i,x,a) for(rg int i=a;ig[maxn];
multisets,t;
ll ans=0;
inline int rd()
while(gc >= '0' && gc <= '9') ret=ret*10+gc-'0',gc=getchar();
return ret*af;
}inline void update(int x)
if(x < l)else r=l;
s.insert(x); s.insert(x); t.insert(r);
return ;
} if(x > r)else l=r;
t.insert(x); t.insert(x); s.insert(l); }}
int main()
if(p > q) swap(p,q),swap(a,b);
g[p].push_back(a);
g[q-1].push_back(b);
if(p+1 <= q-1) f[p+1]++,f[q]--;
} go(i,m+1,1) f[i]+=f[i-1];
l=0; r=inf;
s.insert(l); t.insert(r);
go(i,m+1,1)
go(j,g[i].size(),0) update(g[i][j]);
} printf("%lld",ans);
return 0;
}
紀中集訓2019 11 05
題目鏈結 有 n 個點,求 n 1 個完美匹配,且其中不出現相同的邊。n le 10 3 打暴力 手玩找到規律。把匹配放到方格圖上,給屬於同乙個完美匹配的方格染上同樣的顏色,發現兩個性質 最後一列第一行填 n 之後往下從小到大填完偶數,再從小到大填完奇數 forall i in 1,n 1 從 1,...
紀中集訓 遊戲
題目鏈結 是紀中的題,不過我已經沒有紀中的號了,於是翻出了我的古早部落格 複習的時候又做了一遍,還是想了一會兒的,並且由衷地覺得這真是一道好題。考慮 sg 函式遞推。由於每次操作只能動最後一行和最後一列,那麼設 sg i,j 表示以 i,j 結尾的矩陣的 sg 函式值。轉移有 sg i,j mex ...
紀中集訓2019 3 25 染色問題
有乙個紙片,紙片上有 n 個格仔,初始時沒有顏色 某個遊戲的內容是進行 m 次染色,使得染完後 n 個格仔一定有顏色 每次可以選擇乙個區間 l,r l le r 去染 不能不染 顏色可以覆蓋 問最後染出的序列有多少種 n,m le 10 6 說正解 方程中存在兩類貢獻,一種是 f times j 1...