20210812 數列,數對,最小距離,真相
考場
T1 一眼擴歐,前段時間剛複習過
T2 感覺很可做,但想了很久也不會
T3 畫了畫圖發現可以多源次短路
T4 感覺很可做,想到了根據 $
分段,細節沒想
開 T1,寫完過不了大樣例,看了半天也沒看出來。回頭看草稿紙上的式子,發現少乘了一項,改完又拍出一組錯,發現 \(|x|=|x-k_1|\) 相等是 WA 了,順便改了改暴力,保證它求出的一定正確(while
+assert
)。然後發現拍得太慢,調小資料拍了 \(10^4\) 組就改回去了,又調大了。此時 8.30,感覺很穩
T2 想起以前考過的 一道題,但這題順序不確定,嘗試了各種排序都過不了大樣例,最後 shuffle
走人
T3 寫的很順利,一發過了大樣例,拍上就去上廁所了,回來發現掛了???很慌,害怕假了,改小資料拍出來發現有個地方沒判起點是否相同,然後就過拍了。調資料的時候不知道為什麼,暴力要麼不到 1s 就跑完了,要麼就 10s+,最後選了大資料
9.50 開 T4,此時心態還比較穩健。寫著寫著發現有個地方不會處理,只能 \(O(n^2)\)
res
rk2 100+10+100+0
T2 亂搞一分沒有
T4 改陣列時沒改全,RE 了
rk1 楊哲灝 100+0+100+30
rk2 楊宸驍 10+100+0+100
數列
方程 \(ax+by=c,a\le b\) 的 \(|x|+|y|\) 最小解在 \(x\) 取最小正值或最大負值時取到
考場程式碼
int n; LL a,b,c; LL d,xx,yy,k1,k2,ans; LL exgcd(LL a,LL b) { if( !b ) { xx = 1, yy = 0; return a; } LL d = exgcd(b,a%b); LL z = xx; xx = yy, yy = z - a / b * yy; return d; } signed main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); read(n,a,b); if( a > b ) swap(a,b); d = exgcd(a,b), k1 = b / d, k2 = a / d; For(i,1,n) { read(c); c = -c; if( c % d ) { puts("-1"); return 0; } LL x = (c/d*xx % k1+k1)%k1, y = (c-a*x)/b; if( abs(x-k1)+abs(y+k2) < abs(x)+abs(y) ) x -= k1, y += k2; ans += abs(x)+abs(y); } write(ans); return iocl(); } /* 1 455 824 412 */
數對
考慮同時選兩對數 \((a_i,b_i),(a_j,b_j)\),如果 \(a_i\le b_i,a_j\ge b_i\),那麼 \(i\) 一定在 \(j\) 前面,反之亦然。那麼按 \(a+b\) 排序後 DP 即可
code
const int N = 1e5+5; int n; struct Node { int a,b,w; } a[N]; int mx,lsh[N*2]; LL ans; #define ls (u<<1) #define rs (u<<1|1) namespace seg { struct Node { int l,r; LL mx,add; } t[N*8]; void up(int u) { t[u].mx = max(t[ls].mx,t[rs].mx); } void down(int u,LL x) { t[u].mx += x, t[u].add += x; } void down(int u) { down(ls,t[u].add), down(rs,t[u].add), t[u].add = 0; } void build(int u,int l,int r) { t[u] = Node{l,r,0,0}; if( l == r ) return; int mid = l+r>>1; build(ls,l,mid), build(rs,mid+1,r); } void modify(int u,int p,LL x) { if( t[u].l == t[u].r ) { ckmax(t[u].mx,x); return; } down(u); modify( p<=t[ls].r?ls:rs ,p,x); up(u); } void add(int u,int l,int r,LL x) { if( l <= t[u].l && t[u].r <= r ) { down(u,x); return; } down(u); if( l <= t[ls].r ) add(ls,l,r,x); if( t[rs].l <= r ) add(rs,l,r,x); up(u); } LL query(int u,int l,int r) { if( l <= t[u].l && t[u].r <= r ) return t[u].mx; down(u); LL res = 0; if( l <= t[ls].r ) res = query(ls,l,r); if( t[rs].l <= r ) ckmax(res,query(rs,l,r)); return res; } } #undef ls #undef rs signed main() { read(n); For(i,1,n) read(a[i].a,a[i].b,a[i].w), lsh[++mx] = a[i].a, lsh[++mx] = a[i].b; sort(lsh+1,lsh+mx+1), mx = unique(lsh+1,lsh+mx+1)-lsh-1; For(i,1,n) a[i].a = lower_bound(lsh+1,lsh+mx+1,a[i].a)-lsh, a[i].b = lower_bound(lsh+1,lsh+mx+1,a[i].b)-lsh; sort(a+1,a+n+1,[](const Node &x,const Node &y){return x.a+x.b<y.a+y.b;}); seg::build(1,1,mx); For(i,1,n) { seg::modify(1,a[i].a,seg::query(1,1,min(a[i].a,a[i].b))+a[i].w); if( a[i].a < a[i].b ) seg::add(1,a[i].a+1,a[i].b,a[i].w); } write(seg::t[1].mx); return iocl(); }
最小距離
從特殊點開始一起跑次短路,限制每個點的最短路、次短路必須由不同的特殊點開始
考場程式碼
typedef pair<LL,int> PLI;
const int N = 2e5+5;
int n,m,p,id[N],mm=1,head[N],to[N*2],w[N*2],nxt[N*2];
PLI dis[N],dis2[N];
struct Node { int id; LL dis,dis2; };
bool operator < (const Node &x,const Node &y)
{ return x.dis!=y.dis ? x.dis>y.dis : x.dis2>y.dis2; }
priority_queue<Node> pq;
signed main() {
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
read(n,m,p);
For(i,1,p) read(id[i]);
For(i,1,m) {
int x,y,z; read(x,y,z);
to[++mm] = y, w[mm] = z, nxt[mm] = head[x], head[x] = mm;
to[++mm] = x, w[mm] = z, nxt[mm] = head[y], head[y] = mm;
}
mem(dis,0x3f,n), mem(dis2,0x3f,n);
For(i,1,p) dis[id[i]] = MP(0,id[i]), pq.push(Node{id[i],0,dis2[id[i]].fi});
while( !pq.empty() ) {
Node now = pq.top(); pq.pop();
int u = now.id;
if( dis[u].fi < now.dis || (dis[u].fi==now.dis && dis2[u].fi<now.dis2) )
continue;
// printf("@ %d %lld %lld\n",u,dis[u].fi,dis2[u].fi);
for(int i = head[u], v; v = to[i], i; i = nxt[i]) {
bool flg = 0;
if( dis[u].fi+w[i] < dis[v].fi ) {
if( dis[u].se != dis[v].se ) dis2[v] = dis[v];
dis[v].fi = dis[u].fi+w[i], dis[v].se = dis[u].se, flg = 1;
} else if( dis[u].se != dis[v].se && dis[u].fi+w[i] < dis2[v].fi )
dis2[v].fi = dis[u].fi+w[i], dis2[v].se = dis[u].se, flg = 1;
else if( dis2[u].se != dis[v].se && dis2[u].fi+w[i] < dis2[v].fi )
dis2[v].fi = dis2[u].fi+w[i], dis2[v].se = dis2[u].se, flg = 1;
if( flg ) pq.push(Node{v,dis[v].fi,dis2[v].fi});
}
}
For(i,1,p) write(dis2[id[i]].fi,' ');
return iocl();
}
真相
考場上想的就是正解。。。
考慮以 $
分段,對於每一段如果開始的點真/假確定了,整段正話的數量和最後 $
的真假都確定了