前言
蒟蒻的第三场赛事,终于有会写的题啦,hahaha。
本题涉及题目:
A: [Kirill And The Game]
T1 Kirill And The Game
题面
原题地址: [A]
题意
有两个区间,a属于[l,r],b属于[x,y],问能否使a/b=k。
思路
max(l-r)*max(y-x)=10^14,爆枚O(n^2)直接TLE。
此时,可将a/b=k,变换为k*b=a,这样只用枚举b,看a在不在[l,r]中就行了。
代码
#include<bits/stdc++.h>
using namespace std;
int i,l,r,x,y;
double k;
int main()
{
scanf("%d%d%d%d%lf",&l,&r,&x,&y,&k);
for(i=x;i<=y;i++)
{
if((double)i*k<=r&&(double)i*k>=l)
{
printf("YES");
return 0;
}
}
printf("NO");
return 0;
}
小结
水题*1QWQ(想必有很多人先打爆枚了)。
T2 Gleb And Pizza
题面
原题地址: [B]
题意
有一个内半径为r-d,外半径为r的环,环的圆心在原点上,问给出的n个圆中,有多少个是完全落在环内的。
思路
爆枚。
代码
#include<bits/stdc++.h>
using namespace std;
int r,d,n,x,y,R,ans;
double k;
int main()
{
scanf("%d%d%d",&r,&d,&n);d=r-d;
while(n--)
{
scanf("%d%d%d",&x,&y,&R);
// if(x*x+y*y<=d*d) continue;//原本有这一句就莫名其妙的WA了……;
k=sqrt(x*x+y*y);//圆心离原点的距离;
if((double)k-R>=d&&(double)k+R<=r) ans++;
}
printf("%d",ans);
return 0;
}
小结
水题*2QWQ。
T3 Ilya And The Tree
注:代码抄的
这代码写的是真的好!!!
题面
原题地址: [C]
题意
有一棵树,求每一个节点到根的路径上的所有数的gcd(最多可以忽视一个节点的权值)。
思路
递推+暴力+邻接表。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,cnt,x,y;
int head[N],a[N],f[N],ans[N],father[N];
struct Edge
{
int to, nex;
}e[2*N];
inline void add(int x, int y)
{
e[++cnt].to=y;e[cnt].nex=head[x];head[x]=cnt;
e[++cnt].to=x;e[cnt].nex=head[y];head[y]=cnt;
}
void dfs(int u,int fa)
{
father[u]=fa;
for (int i=head[u];i;i=e[i].nex)
{
int v=e[i].to;
if (v==fa) continue;//防止往回遍历;
f[v]=__gcd(f[u], a[v]);//每一点不删树所得到的gcd;
dfs(v,u);
}
}
void update(int u, int gcd)//将第i点设为断点的情况;
{
ans[u]=max(ans[u],max(gcd,f[u]));//取最大值;
if (gcd==f[u]) return;//对后面的点已经没有可能有不同的gcd了,走f[u]的老路没意义;
for (int i=head[u];i;i=e[i].nex)
{
int v=e[i].to;
if (v==father[u]) continue;
update(v,__gcd(gcd, a[v]));
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y);
f[1]=a[1];
dfs(1,0);
for(int i=1;i<=n;i++) update(i,!father[i]?0:f[father[i]]);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}
小结
最暴力的代码~~~(可惜比优化代码用时用空间少)。
T4 Mike and gcd problem
题面
原题地址: [D]
题意
有n个数字,最少进行几次操作使这n个数的gcd>1,如果不可能输出”NO”。
操作:将a[i],a[i+1]置换成a[i]-a[i+1],a[i]+a[i+1]。
思路
首先,上来先来一次gcd,如果>1,直接输出。然后再看这个操作,置换后的数相加为2*a[i],这让我想起了gcd=2,这时只用考虑奇偶性,即将数转化为1(奇)、0(偶),研究操作的性质发现1,1->0,0 1,0->1,1->0,0 此时我们发现,这个操作数必定有解,so……
PS:然而我不会证此时的操作数必为最小。
代码
#include<bits/stdc++.h>
using namespace std;
int i,n,g,ans,t[100007];
int main()
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&t[i]);
g=__gcd(g,t[i]);//初始的gcd;
t[i]%=2;//为后面的奇偶判断预处理;
}
printf("YES\n");
if(g>1)
{
printf("0");
return 0;
}
for(i=0;i<n;i++)
{
if(t[i])
{
if(t[i+1]) ans++;
else ans+=2;
i++;//此时t[i+1]必定为0;
}
}
printf("%d",ans);
return 0;
}
小结
我把t[n-1]的数拉出来单独算就WA了,又是玄学问题(总而言之水题一个)。
T5 Bank Hacking
题面
原题地址: [E]
题意
有一棵树,每个点都有一个权值,将一个点删去时,与这个点距离<=2的点权值+1,问将所有点删除完之后被删除点的权值的最大值.
思路
PS:这题是我学了邻接表之后补的,邻接表的相关知识可以看我的另一篇博客.
maxn为初始权值的最大值.
我们通过计算发现,删除完所有点之后,除了开始删除的点,与起始点距离为1的点权值+1,其他的点权值+2.这样的话就只有maxn与maxn-1的权值有用了.此时answer只有三中情况:maxn,maxn+1,maxn+2;
情况分类
起始点为maxn时
ans=maxn+2
与初始点距离不为1的点中有maxn;
ans=maxn+1
与初始点距离为1的点中有maxn或与初始点距离不为1的点中有maxn-1;
ans=maxn
除去前两点,剩下就是了;
起始点不为maxn时
ans=maxn+1 特殊情况
所有的maxn都在这个点距离为一的地方…
如:
3
10000 -1 10000
1 2
2 3
此时不判特殊情况就会输出10002,而答案是10001;
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f //int内的最大值;
#define N 300000 //最大点数;
using namespace std;
struct Line
{
int point,next;
}line[N*2+7];
int head[N+7],e,n,i,j,x,y,t[N+7],ans,maxn=-inf,ma,mc,ma_,mc_;
void add(int a,int b)
{
line[e].point=b;
line[e].next=head[a];
head[a]=e;
e++;
}
int main()
{
for(scanf("%d",&n),i=1;i<=n;i++) scanf("%d",&t[i]),maxn=max(maxn,t[i]);
memset(head,-1,sizeof(head));
ans=maxn+3;//初始化,更新方便;
for(i=0;i<n-1;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}//构建邻接表;
for(i=1;i<=n;i++)
{
if(t[i]==maxn) ma++,t[i]=2;
else
if(t[i]==maxn-1) mc++,t[i]=1;
else t[i]=0;
}//搜出maxn的个数(ma),maxn-1的个数(mc),初始化;
for(i=1;i<=n;i++)//对每个点开始搜答案;
{
if(t[i]==2)
{
ma_=0;mc_=0;
for(j=head[i];j!=-1;j=line[j].next)//遍历连通点,搜出连通点中有多少个maxn(ma_),maxn-1(mc_)
{
if(t[line[j].point]==1) mc_++;
else
if(t[line[j].point]==2) ma_++;
}
if(ma-ma_-1) ans=min(ans,maxn+2);
else
{
if(ma_||mc-mc_) ans=min(ans,maxn+1);
else
ans=min(ans,maxn);
}
}
else//特殊情况;
{
ma_=0;
for(j=head[i];j!=-1;j=line[j].next)
{
if(t[line[j].point]==2) ma_++;
}
printf("\n\n");
if(ma_==ma) ans=min(ans,maxn+1);
}
}
printf("%d",ans);
return 0;
}
小结
这个特殊情况极其坑,我没看数据时WA了好多次都是这个,硬是找不出错,直到看了数据才知道这个特殊情况!!!
总结
表示蒟蒻对图这类的东西一窍不通,老师也不讲讲算法,然后这场比赛就跪了。。