FYN OI奋斗之路2~

来源:互联网 发布:mac上传图片 编辑:程序博客网 时间:2024/06/03 08:05

  • XJOI 奋斗群 群赛3
    • A - Kirill And The Game
      • 题意
      • 题解
    • B - Gleb And Pizza
      • 题意
      • 题解
    • C - Ilya And The Tree
      • 题意
      • 题解
    • D - Mike and gcd problem
      • 题意
      • 题解
    • E - Bank Hacking
      • 题意
      • 题解
    • 总结
      • 最终RANK8
      • 待提升
      • FIGHTING

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日
原创粉丝点击