A. Crossmarket
不妨设 \(n\ge m\),则答案为 \(n+2(m-1)\)。
特别地,\(n=1,m=1\) 时答案为 \(0\),注意特判。
View Code
#include<stdio.h>
#include<algorithm>
int T,n,m;
int main() {
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&m);
if (n<m) std::swap(n,m);
if (n==1) puts("0");
else printf("%d\n",n+(m-1<<1));
}
return 0;
}
B. Beautiful Array
为了方便,不妨令 \(0\le a_1,a_2,\cdots,a_{n-1}<k,0\le a_n-kb<k\)。
这样就能保证 beauty 值为 \(b\) 了。
然后问题转化为:
构造 \(n\) 个小于 \(k\) 的非负整数,使它们的和为 \(s-kb\)。
显然 \(0\le s-kb\le n(k-1)\) 时有解,随便做一下就行。
View Code
#include<stdio.h>
#define int long long
int T,n,k,b,s,x;
signed main() {
scanf("%lld",&T);
while (T--) {
scanf("%lld%lld%lld%lld",&n,&k,&b,&s);
if ((s-=k*b)<0) { puts("-1"); continue; }
if ((k-1)*n<s) { puts("-1"); continue; }
for (int i=1; i<n; ++i)
x=(s>=k-1?k-1:s),
printf("%lld ",x),s-=x;
printf("%lld\n",k*b+s);
}
return 0;
}
C. Monoblock
作为一个 C 题来说,感觉出得挺不错的。
考虑 \(a_i\) 对答案的贡献。容易写出式子:
\[[a_i\ne a_{i-1}](i-1)(n-i+1) + [a_i\ne a_{i+1}]i(n-i) \]单点修改显然很好维护。
现在的问题是怎么处理答案的初始值。
其实将读入的序列 \(a\) 当成 \(n\) 次单点修改就好了。
那么我们可以认为最初 \(a_i\) 均为 \(0\),此时的答案即为 \(\dfrac{n(n+1)}2\)。
View Code
#include<stdio.h>
typedef long long ll;
const int N=1e5+5;
int n,m,i,x,a[N]; ll ans;
void upd(int i,int x) {
ll d1=(x!=a[i-1])-(a[i]!=a[i-1]);
ll d2=(x!=a[i+1])-(a[i]!=a[i+1]);
ans+=d1*(i-1)*(n-i+1)+d2*i*(n-i);
a[i]=x;
}
int main() {
scanf("%d%d",&n,&m);
ans=1ll*n*(n+1)>>1;
for (int i=1; i<=n; ++i)
scanf("%d",&x),upd(i,x);
while (m--)
scanf("%d%d",&i,&x),upd(i,x),
printf("%lld\n",ans);
return 0;
}
D. 2+ doors
位运算题,优先考虑能否按位处理。然后发现确实可以。
按位拆分之后目标不变,仍然要让字典序最小。
约束条件分为两类:
- 某两个位置均为 0。
- 某两个位置至少有一个 1。
采取贪心策略,从前往后填数,在满足约束条件的前提下尽量填 0。
对于第 1 类约束条件,预先填 0 即可。
对于第 2 类约束条件,可以建个图,然后乱维护一波。
实现方法比较正常的话,时间复杂度应该是 \(O((n+m)\log V)\),其中 \(V\) 为值域。
View Code
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#define rep(i,l,r) for (int i=l; i<=r; ++i)
#define repE(i,x) for (int i=lst[x]; i; i=E[i].pre)
const int N=1e5+5,M=2e5+5;
int n,m,x,y,w,cnt;
int lst[N],ans[N],v[N];
struct Node { int x,y,w; }Q[M];
struct Edge { int y,pre; }E[M<<1];
inline int read() {
int x=0; char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return x;
}
int main() {
n=read(),m=read();
rep(i,1,m) {
x=read(),y=read(),w=read();
Q[i]={x,y,w};
}
rep(k,0,29) {
cnt=0;
memset(lst,0,sizeof lst);
memset(v,-1,sizeof v);
rep(i,1,m) {
x=Q[i].x,y=Q[i].y,w=(Q[i].w>>k)&1;
if (w&&x!=y)
E[++cnt]={y,lst[x]},lst[x]=cnt,
E[++cnt]={x,lst[y]},lst[y]=cnt;
else v[x]=v[y]=w;
}
rep(i,1,n) if (!v[i]) //已经填0
repE(j,i) v[E[j].y]=1; //相邻点必须填1
rep(i,1,n) {
if (v[i]==1) {
ans[i]|=(1<<k);
continue;
}
v[i]=0;
repE(j,i) v[E[j].y]=1;
}
}
rep(i,1,n) printf("%d ",ans[i]);
return 0;
}
E. Long Way Home
从最简单的情形入手。
\(k=0\) 时就是单源最短路模板,用 dijkstra 做即可。
\(k=1\) 好像就不太会做了。寄
先跑一遍 dijkstra,设从 \(1\) 到 \(i\) 的最短路长度为 \(d_i\)。
现在允许飞一次,那么新的最短路长度 \(d'_i\) 满足
\[d'_i=\min\limits_{1\le j\le n}\{d_j+(i-j)^2\} \]我超,斜率优化。
平时没怎么写过,但可以手搓一下。
时间复杂度为 \(O(n)\)。
注意飞完之后还是可以继续走图上的边的。所以最后再跑一遍 dijkstra。
\(k>1\) 的情况也同理,做 \(k\) 轮 dijkstra 和斜优 dp,最后再加一轮 dijkstra 即可。
dijkstra 堆优化使用 priority_queue
,则总时间复杂度为 \(O(km\log m)\)。
View Code
#include<stdio.h>
#include<queue>
#define rep(i,l,r) for (int i=l; i<=r; ++i)
typedef long long ll;
const int N=1e5+5;
int n,m,k,x,y,w,cnt,lst[N]; ll d[N];
struct Edge { int y,w,pre; }E[N<<1];
struct Node { int x; ll dis; };
bool operator < (Node p,Node q) { return p.dis>q.dis; }
std::priority_queue<Node>Q;
struct Point { int x; ll y; }L[N];
bool cmp(Point a,Point b,Point c,Point d) {
return (a.y-b.y)*(c.x-d.x)>(c.y-d.y)*(a.x-b.x); //k(AB)>k(CD)
}
void dijkstra() {
rep(i,1,n) Q.push({i,d[i]});
while (!Q.empty()) {
Node q=Q.top(); Q.pop();
if (q.dis!=d[q.x]) continue;
for (int i=lst[q.x],y; i; i=E[i].pre)
if (d[y=E[i].y]>d[q.x]+E[i].w) {
d[y]=d[q.x]+E[i].w;
Q.push({y,d[y]});
}
}
}
void dp() {
int l=1,r=0;
rep(i,1,n) { //单调队列维护下凸壳
Point t={i<<1,d[i]+1ll*i*i};
while (l<r&&cmp(L[r-1],L[r],L[r],t)) --r;
L[++r]=t;
}
rep(i,1,n) {
Point t1={0,0},t2={1,i};
while (l<r&&cmp(t1,t2,L[l],L[l+1])) ++l;
d[i]=L[l].y-1ll*L[l].x*i+1ll*i*i;
}
}
int main() {
scanf("%d%d%d",&n,&m,&k);
rep(i,1,m)
scanf("%d%d%d",&x,&y,&w),
E[++cnt]={y,w,lst[x]},lst[x]=cnt,
E[++cnt]={x,w,lst[y]},lst[y]=cnt;
rep(i,2,n) d[i]=1e11;
while (k--) dijkstra(),dp();
dijkstra();
rep(i,1,n) printf("%lld ",d[i]);
return 0;
}
F. Crop Squares
牛逼题,可惜赛时没啥时间想了。
待会再补。
Result: Rank 36 (ABCDE), \(\bf{{\color{purple}{2039}}\to{\color{orange}{2157}}}\),小号2 bcr_233
标签:le,Point,int,rep,Codeforces,dijkstra,Div,include,816 From: https://www.cnblogs.com/REKonib/p/16609814.html