当前位置: 代码迷 >> 综合 >> AtCoder Beginner Contest 133题解
  详细解决方案

AtCoder Beginner Contest 133题解

热度:15   发布时间:2023-11-21 06:58:20.0

AtCoder Beginner Contest 133

A.T or T

◇题目传送门◆

题目大意

给定三个数n,a,bn,a,bn,a,b要求输出n×an\times an×abbb中较小的一个。

分析

简单题,用if语句判断一下就是了。

参考代码

#include<cstdio>
#include<algorithm>
using namespace std;int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifint n,a,b;scanf("%d %d %d",&n,&a,&b);if(n*a>b)printf("%d\n",b);else printf("%d\n",n*a);return 0;
}

B.Good Distance

◇题目传送门◆

题目大意

给定DDD维空间上的NNN个点,要求有多少对点i,ji,ji,j满足i&lt;ji&lt;ji<ji,ji,ji,j间的距离为整数。

DDD维空间中点(y1,y2,…,yD)(y_1,y_2,\ldots,y_D)(y1?,y2?,,yD?)与点(z1,z2,…,zD)(z_1,z_2,\ldots,z_D)(z1?,z2?,,zD?)间距离公式为(y1?z1)2+(y2?z2)2+?+(yD?zD)2\sqrt{(y_1-z_1)^2+(y_2-z_2)^2+\dots+(y_D-z_D)^2}(y1??z1?)2+(y2??z2?)2+?+(yD??zD?)2 ?

分析

由于题目中数据很小,暴力枚举判断即可。

参考代码

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;int N,D;
int X[15][15];bool Check(int i,int j) {
    int x=0;for(int k=1;k<=D;k++)x+=((X[i][k]-X[j][k])*(X[i][k]-X[j][k]));int tmp=sqrt(x);return tmp*tmp==x;
}int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%d %d",&N,&D);for(int i=1;i<=N;i++) {
    for(int j=1;j<=D;j++)scanf("%d",&X[i][j]);}int ans=0;for(int i=1;i<=N;i++)for(int j=i+1;j<=N;j++)if(Check(i,j))ans++;printf("%d\n",ans);return 0;
}

C.Remainder Minimization 2019

◇题目传送门◆

题目大意

给定区间[L,R][L,R][L,R],要求选出i,ji,ji,j使得L≤i&lt;j≤RL\le i&lt;j\le RLi<jR(i×j)mod&ThinSpace;&ThinSpace;2019(i\times j)\mod 2019(i×j)mod2019最小。

分析

我们容易发现当[L,R][L,R][L,R]中有201920192019的倍数时,答案一定为000

那么当[L,R][L,R][L,R]中没有201920192019的倍数时,我们就可以考虑暴力枚举i,ji,ji,j。显然我们可以证明此时R?L+1≤2019R-L+1\le 2019R?L+12019,所以总时间复杂度为O(20192)O({2019}^2)O(20192),不会超时。

参考代码

#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;map<long long,int> m;int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endiflong long l,r;scanf("%lld %lld",&l,&r);if(r/2019-(l-1)/2019>0) {
    puts("0");return 0;}long long ans=0x3f3f3f3f;for(long long i=l;i<=r;i++)for(long long j=i+1;j<=r;j++)ans=min(ans,i*j%2019);printf("%lld\n",ans);return 0;
}

D.Rain Flows into Dams

◇题目传送门◆

题目大意

NNN座山围成一圈(NNN为奇数),从111NNN标号。约定000NNNN+1N+1N+1111

iii和第i+1i+1i+1座山之间有一座水库,标号为iii

当第iii座山下2x2x2x个单位雨时,第iii和第i?1i-1i?1座水库就能收到xxx单位水。

给定每个水库收到的水量AiA_iAi?,求每座山的雨量。

分析

我们记TiT_iTi?为第iii座山的雨量。

则我们可列出方程:{T1+T22=A1T2+T32=A2T3+T42=A3……TN?1+TN2=AN?1TN+T12=AN\begin{cases}\frac{T_1+T_2}{2}=A_1\\\frac{T_2+T_3}{2}=A_2\\\frac{T_3+T_4}{2}=A_3\\\ \ \dots\ \ \ \ \ \ \dots\\\frac{T_{N-1}+T_N}{2}=A_{N-1}\\\frac{T_N+T_1}{2}=A_N\end{cases}????????????????????2T1?+T2??=A1?2T2?+T3??=A2?2T3?+T4??=A3?        2TN?1?+TN??=AN?1?2TN?+T1??=AN??

整理一下:{T1+T2=2A1(1)T2+T3=2A2(2)T3+T4=2A3(3)……TN?1+TN=2AN?1(N?1)TN+T1=2AN(N)\begin{cases}T_1+T_2=2A_1&amp;(1)\\T_2+T_3=2A_2&amp;(2)\\T_3+T_4=2A_3&amp;(3)\\\ \ \dots\ \ \ \ \ \ \dots\\T_{N-1}+T_N=2A_{N-1}&amp;(N-1)\\T_N+T_1=2A_N&amp;(N)\end{cases}????????????????????T1?+T2?=2A1?T2?+T3?=2A2?T3?+T4?=2A3?        TN?1?+TN?=2AN?1?TN?+T1?=2AN??(1)(2)(3)(N?1)(N)?

(1)+(2)+(3)+?+(N)2\frac{(1)+(2)+(3)+\dots+(N)}{2}2(1)+(2)+(3)+?+(N)?得:∑i=1NTi=∑i=1NAi\sum_{i=1}^{N}T_i=\sum_{i=1}^{N}A_ii=1N?Ti?=i=1N?Ai?

又因为NNN是一个奇数,所以我们可以发现,将奇数号方程左边相加,我们发现T2T_2T2?TNT_NTN?都出现了一次,仅有T1T_1T1?出现了一次,所以:

(1)+(3)+(5)+?+(N)(1)+(3)+(5)+\dots+(N)(1)+(3)+(5)+?+(N)得:T1+∑i=1NTi=∑k=1N?12A2k?1T_1+\sum_{i=1}^{N}T_i=\sum_{k=1}^{\frac{N-1}{2}}A_{2k-1}T1?+i=1N?Ti?=k=12N?1??A2k?1?

两式相减即可解得T1T_1T1?,再顺次带入各个方程即可解得所有解。

参考代码

#include<cstdio>
#include<algorithm>
using namespace std;const int Maxn=1e5;int N,A[Maxn+5];int ans[Maxn+5];int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%d",&N);for(int i=1;i<=N;i++)scanf("%d",&A[i]);int sum=0,tmp=0;for(int i=1;i<=N;i++) {
    if(i&1)tmp+=2*A[i];sum+=A[i];}ans[1]=tmp-sum;for(int i=2;i<=N;i++)ans[i]=2*A[i-1]-ans[i-1];for(int i=1;i<=N;i++)printf("%d ",ans[i]);return 0;
}

E.Virus Tree 2

◇题目传送门◆

题目大意

给定一棵有NNN个节点的树和KKK种颜色,要求给每个点涂上颜色,使得距离小于等于222的两个节点不同色,问方案数模109+710^9+7109+7

分析

画一下图就可以发现,只要点的深度大于222且当前节点有nnn个兄弟节点,那么该层可选的颜色数为∏i=0n?1K?2?i\prod_{i=0}^{n-1} K-2-ii=0n?1?K?2?i,当一个点深度小于222且其兄弟节点个数为nnn则该点的可选颜色种数为∏i=0n?1K?i?当前节点深度\prod_{i=0}^{n-1}K-i-当前节点深度i=0n?1?K?i?

由乘法原理,将所有点的可选颜色数乘起来即可。

参考代码

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;typedef long long ll;
const int Maxn=1e5;
const ll Mod=1000000007;int N,K;
vector<int> G[Maxn+5];
void addedge(int u,int v) {
    G[u].push_back(v);G[v].push_back(u);
}long long ans;long long DFS(int u,int fa,int dep) {
    int tmp=K-min(dep,2);for(int i=0;i<(int)G[u].size();i++) {
    int v=G[u][i];if(v==fa)continue;if(DFS(v,u,dep+1)==0)return 0;ans=ans*tmp%Mod;tmp--;}return ans;
}int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifscanf("%d %d",&N,&K);for(int i=1;i<N;i++) {
    int u,v;scanf("%d %d",&u,&v);addedge(u,v);}ans=K;printf("%lld\n",DFS(1,-1,1));return 0;
}

F.Colorful Tree

◇题目传送门◆

前言

ABC怎么会出现可持久化线段树+LCA???

第一次ABC做到这么难的题。。。

不是ABC一般都出的贪心,简单DP之类的东西吗???(逃

所以以后还是要认真对待ABC了。

题目大意

给定一棵有NNN个节点的树,每条边都有一个颜色和长度。现给出QQQ个查询,每个查询先将所有颜色值为ccc的边的长度改为ddd,再查询节点uuu到节点vvv的最短距离。

每次查询独立,互不影响。

分析

由于直接查询复杂度为O(NQ)O(NQ)O(NQ),在题目中的条件下这个复杂度显然会爆,所以我们不能暴力。

我们记根节点111到当前节点uuu的距离为d(u)d(u)d(u)。计算所有d(u)d(u)d(u)的复杂度为O(N)O(N)O(N)

考虑LCA,利用LCA,原始路径长度转化为d(u)+d(v)?2×d(LCA(u,v))d(u)+d(v)-2\times d(LCA(u,v))d(u)+d(v)?2×d(LCA(u,v))。我们使用倍增LCA可以使得到这个结果的复杂度降至O(log?2N)O(\log_2 N)O(log2?N)

那么我们如何记录每条路径上某种颜色的边数和该颜色的边的长度和呢?

没错,我们就要用到可持久化数组了。但为了保证复杂度,我们将它用可持久化线段树来写。(只需实现单点修改和查询,连回传更新都可以不要)

线段树中以颜色为下标,第uuu个历史版本记录从根节点到节点uuu的路径上各种颜色的出现次数和该种颜色的长度,计算uuuvvv的路径上的某种颜色的边数和该颜色的边的长度的方法和计算原始路径长度的方法类似。

初始化LCA和可持久化线段树的时间复杂度均为O(Nlog?2N)O(N\log_2 N)O(Nlog2?N),查询一次需要的复杂度为O(log?2N)O(\log_2 N)O(log2?N)。初始化LCA和可持久化线段树以及ddd数组的总时间复杂度为O(Nlog?2N)O(N\log_2 N)O(Nlog2?N),查询总时间为O(Qlog?2N)O(Q\log_2 N)O(Qlog2?N),故总时间复杂度为O((N+Q)log?2N)O((N+Q)\log_2 N)O((N+Q)log2?N),非常优秀,在AtCoder上可以跑约250ms。

据说还可以用复杂度为O((N+Q)N)O((N+Q)\sqrt{N})O((N+Q)N ?)的树上莫队(听说很复杂。。。也没学过。。。)或者复杂度为O(N)O(N)O(N)离线LCA算法(没学,逃。。。)来做。。。

参考代码

#include<cstdio>
#include<algorithm>
using namespace std;const int Maxn=1e5;
const int Maxlogn=17;int N;struct Edge {
    static Edge *ecnt;int to,dis,col;Edge *nxt;
};
Edge e[2*Maxn+5];
Edge *G[Maxn+5];
Edge* Edge::ecnt=&e[0];
void addedge(int u,int v,int c,int d) {
    Edge *p=++Edge::ecnt;p->to=v,p->dis=d,p->col=c;p->nxt=G[u],G[u]=p;
}struct SegmentTree {
    struct Segment {
    int cnt,sum;Segment *ch[2];};Segment t[Maxn*25+5];Segment *ncnt,*NIL;SegmentTree() {
    NIL=ncnt=&t[0];NIL->ch[0]=NIL->ch[1]=NIL;}Segment * newnode() {
    Segment *ret=++ncnt;ret->cnt=ret->sum=0;ret->ch[0]=ret->ch[1]=NIL;return ret;}Segment * add(Segment *pre,int l,int r,int pos,int val) {
    Segment *rt=newnode();(*rt)=(*pre);if(l==r) {
    rt->cnt++,rt->sum+=val;return rt;}int mid=(l+r)>>1;if(pos<=mid)rt->ch[0]=add(pre->ch[0],l,mid,pos,val);else rt->ch[1]=add(pre->ch[1],mid+1,r,pos,val);return rt;}void query(Segment *rt,int l,int r,int pos,int &ret_cnt,int &ret_sum) {
    if(l==r) {
    ret_cnt=rt->cnt;ret_sum=rt->sum;return;}int mid=(l+r)>>1;if(pos<=mid)query(rt->ch[0],l,mid,pos,ret_cnt,ret_sum);else query(rt->ch[1],mid+1,r,pos,ret_cnt,ret_sum);}
};
SegmentTree T;
SegmentTree::Segment *RT[Maxn+5];int dep[Maxn+5];
int dis[Maxn+5];
int fa[Maxlogn+5][Maxn+5];
void DFS(int u,int par,int depth) {
    dep[u]=depth;fa[0][u]=par;for(int i=1;i<=Maxlogn;i++)fa[i][u]=fa[i-1][fa[i-1][u]];for(Edge *p=G[u];p!=NULL;p=p->nxt) {
    int v=p->to;if(v==par)continue;RT[v]=T.add(RT[u],1,N,p->col,p->dis);dis[v]=dis[u]+p->dis;DFS(v,u,depth+1);}
}int CalcLCA(int u,int v) {
    if(dep[u]<dep[v])swap(u,v);for(int i=Maxlogn;i>=0;i--)if(dep[fa[i][u]]>=dep[v])u=fa[i][u];if(u==v)return u;for(int i=Maxlogn;i>=0;i--)if(fa[i][u]!=fa[i][v])u=fa[i][u],v=fa[i][v];return fa[0][u];
}int main() {
    #ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifint Q;scanf("%d %d",&N,&Q);for(int i=1;i<N;i++) {
    int u,v,c,d;scanf("%d %d %d %d",&u,&v,&c,&d);addedge(u,v,c,d);addedge(v,u,c,d);}RT[1]=T.NIL;DFS(1,0,1);while(Q--) {
    int c,d,u,v;scanf("%d %d %d %d",&c,&d,&u,&v);int lca=CalcLCA(u,v);int c1,c2,c3,d1,d2,d3;T.query(RT[u],1,N,c,c1,d1),T.query(RT[v],1,N,c,c2,d2),T.query(RT[lca],1,N,c,c3,d3);int totc=c1+c2-2*c3,totd=d1+d2-2*d3,pred=dis[u]+dis[v]-2*dis[lca];printf("%d\n",pred-totd+d*totc);}return 0;
}
  相关解决方案