XJOI 奋斗群 群赛3
A - Kirill And The Game
题意
输入两个区间l-r、x-y和一个数k,判断是否能在第一个区间找出一个数a,第二个区间找出一个数b,使得a除以b等于k。
题解
遍历一遍第一个区间,找出是否能使a*k在第二个区间范围内,若能,输出“Yes“,否则输出”No“。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long int l,r,x,y,ans,k;
cin>>l>>r>>x>>y>>k;
for(int i=x;i<=y;i++){
ans=i*k;
if(ans>=l&&ans<=r){
cout<<"YES";
return 0;
}
}
cout<<"NO";
return 0;
}
B - Gleb And Pizza
题意
输入一个大圆半径r和外环宽度d,再输入n个小圆的相关参数:圆心的坐标(x,y)和半径l。求出不在外环上的小圆个数(原题用的比萨和香肠2333)
题解
由于数据比较小,依次判断每一个小圆是否符合要求即可,需要注意外环宽度为0,小圆半径为0的情况比较特殊。
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b,n;
int dis;
int ans=0;
int x[100000],y[100000],r[100000];
scanf("%d %d %d",&a,&b,&n);
b=a-b;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&x[i],&y[i],&r[i]);
dis=x[i]*x[i]+y[i]*y[i];
if(b!=0){
if(dis<=(a-r[i])*(a-r[i])&&dis>=(b+r[i])*(b+r[i])) ans++;
}
else{
if(r[i]==0){
if(a*a==dis) ans++;
}
}
}
cout<<ans;
}
C - Ilya And The Tree
题意
有一棵树,每个结点有一权值,求对于每个结点,根节点到该结点的所有数的最大公约数(对于每一条路径,可将一个数改为0,gcd(a,0)=a。
题解
建树用set存储每一条路径的gcd值,方法很简单但不太会建树所有拖了比较久。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=200100;
int ans[MAXN]={0},first[MAXN]={0},a[MAXN]={0},t[MAXN]={0},n,cnt;
bool visit[MAXN];
struct edge{
int to,next;
}e[MAXN];
set <int> ans1[MAXN];
int gcd(int a,int b){
int x;
while(b!=0){
x=a;
a=b;
b=x%b;
}
return a;
}
void dfs(int x){
visit[x]=true;
int k=first[x];
ans[x]=gcd(ans[t[x]],a[x]);
ans1[x].insert(ans[t[x]]);
set <int>::iterator it=ans1[t[x]].begin();
while(it!=ans1[t[x]].end()){
ans1[x].insert(gcd(*it,a[x]));
it++;
}
while(k!=0){
if(!visit[e[k].to]){
t[e[k].to]=x;
dfs(e[k].to);
}
k=e[k].next;
}
}
int main(){
memset(visit,false,sizeof(visit));
int x,y,k;
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);
e[++cnt].to=y;
e[cnt].next=first[x];
first[x]=cnt;
e[++cnt].to=x;
e[cnt].next=first[y];
first[y]=cnt;
}
ans[1]=a[1];
ans1[1].insert(0);
visit[1]=true;
k=first[1];
while(k!=0){
t[e[k].to]=1;
dfs(e[k].to);
k=e[k].next;
}
set <int>::reverse_iterator it;
for(int i=1;i<=n;i++){
it=ans1[i].rbegin();
printf("%d ",max(*it,ans[i]));
}
return 0;
}
D - Mike and gcd problem
题意
输入一串n个数组成的序列,要求求出最少的操作次数使得该数列的最大公约数大于1,每一次操作可将数字a[i]、a[i+1]用a[i]-a[i+1]、a[i]+a[i+1]。若无法完成,输出”No“。
题解
先判断初始的最大公约数是否大于1,若不不大于1,则要将其变为2,将奇奇变成偶偶需要一次操作,将奇偶或偶奇变成偶偶需要两次操作。所以先处理奇奇,然后再处理其他情况。用贪心写即可。
#include<bits/stdc++.h>
using namespace std;
int gcd(int num1,int num2){
if(num1<0) num1=abs(num1);
else if(num2<0) num2=abs(num2);
int m1=max(num1,num2);
int m2=min(num1,num2);
if(num1==0||num2==0){
return m1;
}
else{
for(int i=m2;i>=1;i--){
if(num1%i==0&&num2%i==0) return i;
}
}
}
int main(){
int n,a[100001];
scanf("%d",&n);
int count=0,ans=0,flag=0;
int num,temp;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]!=0) flag=1;
}
if(flag==1){
for(int i=2;i<=n;i++){
if(i==2)num=gcd(a[1],a[i]);
else num=gcd(num,a[i]);
}
if(num!=1) printf("YES\n0");
else{
for(int i=1;i<=n-1;i++){
if(a[i]%2==1&&a[i+1]%2==1){
count++;
temp=a[i];
a[i]=temp-a[i+1];
a[i+1]=temp+a[i+1];
}
}
for(int i=1;i<=n;i++){
if(a[i]%2==0&&a[i+1]%2==1){
count=count+2;
temp=a[i];
a[i]=temp-a[i+1];
a[i+1]=temp+a[i+1];
temp=a[i];
a[i]=temp-a[i+1];
a[i+1]=temp+a[i+1];
}
if(a[i]%2==1&&a[i+1]%2==0){
count=count+2;
temp=a[i];
a[i]=temp-a[i+1];
a[i+1]=temp+a[i+1];
temp=a[i];
a[i]=temp-a[i+1];
a[i+1]=temp+a[i+1];
}
}
printf("YES\n%d",count);
}
}
else printf("NO");
}
E - Bank Hacking
题意
有n个点,每个点有初始的实力,给出n-1条线使两点之间互相连接,之后攻击某一个点,第一个点只要求实力大于该点实力,攻击一个点后与改点相邻(直接相连)或半相邻(用两条线相连)的点实力会加1。第二个点需要与被攻击的点相邻。
题解
每个点的实力最多提升2次,因此只要可以分两类讨论:
1.若只有一个最大的点,只需枚举该点相邻的点即可,若所有的权值等于最大值-1的点都与该点相邻或半相邻,输出最大值即可,反之,输出最大值+1;
2.若最大的点不止一个,对于每个最大的点,枚举相邻与半相邻的点,若所有最大的点都互相相邻或半相邻,输出最大值+1,反之,输出最大值+2。
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9+10;
vector <int> a[1000000];
int power[10000000],start,end;
int main(){
int n,m=-inf,temp;
int count1=0,count2=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&power[i]);
m=max(m,power[i]);
}
for(int i=1;i<=n-1;i++){
scanf("%d %d",&start,&end);
a[start].push_back(end);
a[end].push_back(start);
}
for(int i=1;i<=n;i++){
if(power[i]==m) {
count1++;
temp=i;
}
else if(power[i]==m-1) count2++;
}
if(count1==1){
int cnt=0;
for(int i=0;i<a[temp].size();i++){
if(power[a[temp][i]]==m-1) cnt++;
}
if(cnt==count2) printf("%d",m);
else printf("%d",m+1);
}
else{
bool flag=false;
for(int i=1;i<=n;i++){
int cnt=0;
if(power[i]==m) cnt++;
for(int j=0;j<a[i].size();j++){
if(power[a[i][j]]==m) cnt++;
}
if(cnt==count1) flag=true;
}
if(flag) printf("%d",m+1);
else printf("%d",m+2);
}
return 0;
}
总结
最终RANK:8
待提升
因数据范围问题导致的错误比较多,注意特殊情况的单独讨论。
FIGHTING!
2017年9月5日