test37
-
没有大样例。
-
小样例无法复制。
-
没有部分分。
-
题解几句话。
-
证明留作作业。
-
就给个std。
-
三道图论。
-
四题都是问最小代价。
-
交换来的。
均分纸牌
猜测上界是 \(n-1\),所以现在希望每个间隔是经过一次,因为间隔左右的和是一定的,所以这个操作的权值肯定容易确定。考虑会有多少值流过这个间隔,如果非 \(0\) 的话就是 \(i-1\) 达到 \(flow\) 可以流向 \(i\) / \(i\) 达到 \(flow\) 可以流向 \(i-1\)。因为要字典序最优,那么贪心操作可以操作的最好的地方即可,显然总有点可以操作,并且操作之后这个间隔未来无用。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)using namespace std;const int N=300005;int n, a[N], s[N], ave, L[N], R[N], ans;
priority_queue<int,vector<int>,greater<int> > q;signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n;up(i,1,n) cin >> a[i], s[i]=s[i-1]+a[i];ave=s[n]/n;up(i,1,n-1) {int flow=s[i]-ave*i;if(flow) ++ans;if(flow>0) R[i]=flow; else L[i+1]=-flow;}cout << ans << '\n';up(i,1,n) if(L[i]&&a[i]>=L[i]||R[i]&&a[i]>=R[i]) q.push(i);while(q.size()) {int i=q.top();q.pop();if(L[i]&&a[i]>=L[i]) {cout << i << ' ' << i-1 << ' ' << L[i] << '\n';a[i]-=L[i], a[i-1]+=L[i], L[i]=0;if(R[i]&&a[i]>=R[i]) q.push(i);if(L[i-1]&&a[i-1]>=L[i-1]||R[i-1]&&a[i-1]>=R[i-1]) q.push(i-1);}else if(R[i]&&a[i]>=R[i]) {cout << i << ' ' << i+1 << ' ' << R[i] << '\n';a[i]-=R[i], a[i+1]+=R[i], R[i]=0;if(L[i+1]&&a[i+1]>=L[i+1]||R[i+1]&&a[i+1]>=R[i+1]) q.push(i+1);}}return 0;
}
吞噬变异
转移是 \(p_c=\min\{p_c,p_a+p_b\}\),我们现在要找一个复杂度正确的松弛顺序。
此时 \(p_u=\min\{p_i\}\) 的 \(p_u\) 肯定被确定了,我们希望更新掉 \(a/b=u\) 的贡献然后删除(或者说未来不考虑)\(u\),好像不能直接删,因为可能会有 \((a,b,c)\) 需要 \((p,q,b)\) 的前置,虽然我们不好动态松弛掉 \(p_u\) 的所有贡献,但是按照顺序确定好像可以诶,就是你考虑拿 \(p_u\) 作为 \(a/b\) 另一个 \(b/a\) 用比 \(p_u\) 更小的 \(v\),然后去松弛,不过讲真的我感觉我对这个理解不够透彻,感觉是合并的使用是一个 DAG 这样可以扫出来吧。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define pb push_back
#define mp make_pair using namespace std;const int N=100005;int n, m, tag[N], dis[N];
vector<pii> to[N];
priority_queue<pii,vector<pii>,greater<pii> > q;signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m;up(i,1,n) cin >> dis[i];while(m--) {int u, v, w;cin >> u >> v >> w;to[u].pb(mp(v,w));to[v].pb(mp(u,w));}up(i,1,n) q.push(mp(dis[i],i));while(q.size()) {int x=q.top().second;q.pop();if(tag[x]) continue;tag[x]=1;for(pii u:to[x]) {int y=u.first, w=u.second;if(tag[y]&&dis[x]+dis[y]<dis[w]) {dis[w]=dis[x]+dis[y];q.push(mp(dis[w],w));} }}up(i,1,n) cout << dis[i] << ' ';return 0;
}
连线问题
证明留作作业都来了。
你去脑测一个 kruskal 的过程,你可能连到 \(a/b\) 里面的邻边,不然你就要连叉边,那是在你前继连通块的基础上增加的,发现拓展会一直保持连到前后继的形态。所以找到前后继承的边和相邻边扔着跑跑 mst 就好了。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define ldb long double
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)using namespace std;const int N=2500005;int n, m, tot, A, B, a[N], b[N], dsu[N];
ldb Ans;
struct node { int x, y; ldb w; } p[N];inline ldb pw(ldb x) { return x*x; }
int get(int x) { return x==dsu[x]?x:dsu[x]=get(dsu[x]); }signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m >> A >> B;up(i,1,n) cin >> a[i], a[i]+=a[i-1];up(i,1,m) cin >> b[i], b[i]+=b[i-1];up(i,2,n) p[++tot]=(node){i-1,i,a[i]-a[i-1]};up(i,2,m) p[++tot]=(node){n+i-1,n+i,b[i]-b[i-1]};up(i,1,n) {int l=upper_bound(b+1,b+1+m,a[i])-b-1;int r=lower_bound(b+1,b+1+m,a[i])-b;if(1<=l&&l<=m) p[++tot]=(node){i,n+l,sqrtl(pw(a[i]-b[l])+pw(A-B))};if(1<=r&&r<=m) p[++tot]=(node){i,n+r,sqrtl(pw(a[i]-b[r])+pw(A-B))};}up(i,1,n+m) dsu[i]=i;sort(p+1,p+1+tot,[](node i,node j){return i.w<j.w;});up(i,1,tot) {int x=get(p[i].x), y=get(p[i].y);if(x!=y) Ans+=p[i].w, dsu[x]=y;}cout << fixed << setprecision(2) << (double)Ans << '\n';return 0;
}
走迷宫
晕了,就是按照题意模拟广搜出来,没啥好说的,具体看代码。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define x first
#define y second
#define pii pair<int,int>
#define mp make_pairusing namespace std;const int N=100005, inf=1e9;int n, m;
pii S, a[N];
unordered_map<int,set<int> > X, Y;
unordered_map<int,map<int,int> > p, q;
queue<pair<pii,int> > qwq;pii query(set<int> &suf,int v) {pii ret=mp(0,0);auto it=suf.lower_bound(v);if(it!=suf.end()) ret.second=*it;if(it!=suf.begin()) ret.first=*--it;return ret;
}void solve(unordered_map<int,set<int> > &X,unordered_map<int,map<int,int> > &p) {for(pair<int,set<int> > stain:X) {int x=stain.x;set<int> now=stain.second;map<int,int> nxt;now.insert(inf);for(int r:now) {int res=inf;while(p[x].size()) {auto it=p[x].begin();if(it->x==r) { p[x].erase(it), nxt[r]=p[x][r]; continue; }if(it->x>r) break;res=min(res,it->second), p[x].erase(it);} if(res<inf) nxt[r-1]=res;}p[x]=nxt; }
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m >> S.x >> S.y;up(i,1,n) {cin >> a[i].x >> a[i].y;X[a[i].x].insert(a[i].y);Y[a[i].y].insert(a[i].x);}p[S.x][S.y]=1, qwq.push(mp(S,0));q[S.y][S.x]=1, qwq.push(mp(S,1));while(qwq.size()) {int type=qwq.front().y;pii u=qwq.front().x;qwq.pop();if(type==0) {pii sav=query(X[u.x],u.y);int l=sav.first, r=sav.second;if(l&&l+1<u.y&&q[l+1].find(u.x)==q[l+1].end()) {q[l+1][u.x]=p[u.x][u.y]+1;qwq.push(mp(mp(u.x,l+1),1));} if(r&&u.y<r-1&&q[r-1].find(u.x)==q[r-1].end()) {q[r-1][u.x]=p[u.x][u.y]+1;qwq.push(mp(mp(u.x,r-1),1));} }else {pii sav=query(Y[u.y],u.x);int l=sav.first, r=sav.second;if(l&&l+1<u.x&&p[l+1].find(u.y)==p[l+1].end()) {p[l+1][u.y]=q[u.y][u.x]+1;qwq.push(mp(mp(l+1,u.y),0));}if(r&&u.x<r-1&&p[r-1].find(u.y)==p[r-1].end()) {p[r-1][u.y]=q[u.y][u.x]+1;qwq.push(mp(mp(r-1,u.y),0));} }}solve(X,p), solve(Y,q);while(m--) {int x, y, ans=inf;cin >> x >> y;if(mp(x,y)==S) { cout << 0 << '\n'; continue; }if(p[x].find(y)!=p[x].end()) ans=min(ans,p[x][y]);if(q[y].find(x)!=q[y].end()) ans=min(ans,q[y][x]);auto L=p[x].lower_bound(y), R=L; pii u=query(X[x],y); int l=u.first, r=u.second;if(L!=p[x].end()) if(!r||r>L->first) ans=min(ans,L->second);if(L!=p[x].begin()) {--R;if(!l||l<R->first) ans=min(ans,R->second);}L=q[y].lower_bound(x), R=L, u=query(Y[y],x), l=u.first, r=u.second;if(L!=q[y].end()) if(!r||r>L->first) ans=min(ans,L->second);if(L!=q[y].begin()) {--R;if(!l||l<R->first) ans=min(ans,R->second);}if(ans==inf) ans=-1;cout << ans << '\n';}return 0;
}