czl蒻蒟的OI之路2

来源:互联网 发布:如何做数据透视表 编辑:程序博客网 时间:2024/05/16 13:42

  • XJOI奋斗群蒻蒟群群赛3 RANK排名7
      • T1Kirill And The GameTLE一次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T2Gleb And PizzaWA一次后AC
          • 题意
          • 分析过程
          • 给出题解
      • T3Ilya And The Tree 已AC
          • 题意
          • 分析过程
          • 给出题解
      • T4Mike and gcd problem WA两次后AC
          • 题意
          • 分析过程
          • 给出题解
      • 蒻蒟总结

—>XJOI奋斗群(蒻蒟群)群赛3<— RANK排名7

T1:Kirill And The Game(TLE一次后AC)

题意:

给你两个区间l到r,x到y,让你求在这个区间中是否存在两个数a,b,使得a在第一个区间中,b在第二个区间中,并且a/b的值为给出的数k。

分析过程:

刚开始想都没想就写了两个for循环,计算每个k的值,再去进行比较,果断TLE。然后思考了一下,发现这题根本不用这样做,只要列举第二个区间的所有整数,再乘k,看是否有乘积落在第一个区间中,如果有,就输出YES,反之输出NO,这样还省的用double。

给出题解:
#include<bits/stdc++.h>using namespace std;int main(){    bool flag=false;    long long int l,r,x,y,xiaolv,k;    cin>>l>>r>>x>>y>>k;    for(int i = x; i <= y ; i++)    {        xiaolv =i*k;        if(xiaolv>=l&&xiaolv<=r){flag=true;break;}    }    if(flag==true)cout<<"Yes";    else cout<<"No";}

T2:Gleb And Pizza(WA一次后AC)

题意:

给你一个披萨,整个半径为r,外面壳的半径为d。披萨的圆心再原点上。然后披萨上面有一些圆形的香肠片,给出每个香肠片的圆心的坐标和半径,问你有几个香肠片是完全在壳上的。

分析过程:

刚开始以为这题就只是需要模拟一下就行了。可是交了一次才发现这题数据是有多么的坑。首先是d的值,给出的数据中,可能会出现d的值是0的情况,然而这个时候并不是指这个披萨是没有壳的,而是指这个披萨的壳就是紧紧的贴在内圆上的(净扯!)。然后是香肠片的半径,同样也会出现值为0的情况,与壳相同,这并不是指不存在这个香肠片了,而是这个香肠片是个点(又扯!)。所以只要把这些特殊的数据加以处理一下,其他的都比较简单。还有就是我的代码里没用sqrt,毕竟数据比较大,还有100个测试点,怕是要TLE。

给出题解:
#include<bits/stdc++.h>#define maxn 100010using namespace std;int get_dis(int x,int y){    int dis=x*x+y*y;    return dis;}int main(){    int r1,r2;    int n;    int x[maxn],y[maxn],r[maxn];    int dis,dis2,dis3;    int cnt=0;    cin>>r1>>r2>>n;    if(r2!=0)    {        r2=r1-r2;        for(int i=1;i<=n;i++)        {        cin>>x[i]>>y[i]>>r[i];        dis=get_dis(x[i],y[i]);        dis2=(r1-r[i])*(r1-r[i]);        dis3=(r2+r[i])*(r2+r[i]);        if(dis<=dis2&&dis>=dis3)cnt++;        }    }    else     {        for(int i=1;i<=n;i++)        {        cin>>x[i]>>y[i]>>r[i];        if(r[i]==0)        {        dis=get_dis(x[i],y[i]);        if(dis==r1*r1)cnt++;        }        }    }    cout<<cnt;}

T3:Ilya And The Tree (已AC)

题意:

给出一棵生成树,每个节点都有一个值,现在要求出每个节点的美丽值的最大值,美丽值的定义为从根节点到该节点(包含)路径上所有点的值的gcd,求解每个点时可以把路径上某一个点的值变为0。你可以认为每个点美丽值的求解是独立的。

分析过程:

可以用树形DFS,我们用dp数组来保存每个节点在路径上没有改变值的时候的gcd,然后先单独考虑当前点不选的美丽值即dp[u]。然后用vector[u]数组来保存节点v的父亲节点的美丽值的所有可能情况,这里的情况有可能是改变了值后的,也可能没有,但由于我们在这一步一定会算入节点v的值(不算的情况单独考虑),所以满足最多只改变一次值的要求。

给出题解:
#include<bits/stdc++.h> using namespace std;  #define mst(a,b) memset((a),(b),sizeof(a))  typedef long long ll;  const int maxn = 200005;  const ll mod = 1e9+7;  const int INF = 0x3f3f3f3f;  const double eps = 1e-9;  int gcd(int a,int b)  {      return b?gcd(b,a%b):a;  }  int n,cnt;  int a[maxn],dp[maxn];  int head[maxn];  vector<int>vec[maxn];  struct node  {      int v,next;  }e[maxn*2];  void add(int u,int v)  {      e[cnt].v=v;      e[cnt].next=head[u];      head[u]=cnt++;  }  void dfs(int u,int pre)  {      for(int i=head[u];~i;i=e[i].next)      {          int v=e[i].v;          if(v==pre) continue;          dp[v]=gcd(dp[u],a[v]);          vec[v].push_back(dp[u]);          for(int i=0;i<vec[u].size();i++)          {              vec[v].push_back(gcd(vec[u][i],a[v]));          }          sort(vec[v].begin(),vec[v].end());                     //????          vec[v].erase(unique(vec[v].begin(),vec[v].end()),vec[v].end());          dfs(v,u);      }  }  int main()  {  //    freopen("in.txt","r",stdin);    mst(head,-1);      cnt=0;      cin>>n;     for(int i=1;i<=n;i++)      {          cin>>a[i];     }      int x,y;      for(int i=0;i<n-1;i++)      {          cin>>x>>y;          add(x,y);          add(y,x);      }      dp[1]=a[1];      vec[1].push_back(0);      dfs(1,-1);      for(int i=1;i<=n;i++)      {          dp[i]=max(dp[i],vec[i].back());       }      for(int i=1;i<n;i++)      {          cout<<dp[i]<<" ";    }      cout<<dp[n];      return 0;}

T4:Mike and gcd problem (WA两次后AC)

题意:

给你一个串数列,你可执行的操作便是选出a[i]和a[i+1]这两个数,分别用a[i]-a[i+1]和a[i]+a[i+1]替换。操作到最后,让这个数列的最大公约数大于1。如果可以的话,输出YES和需要的步数,如果不行,就输出NO。

分析过程:

这题如果想出了方法就比较简单了。既然是要最大公约数大于1,那么最容易达到的肯定就是2了,因为2的倍数多的要命啊。而且两个奇数只需一次上述操作就可以变成两个偶数,而一奇一偶则只需两次操作就可以变成两个偶数,所以让最大公约数变成2应该是最快的。然后就是怎么变了,刚开始没有看到这两个数必须是相邻的数,只是简简单单的判断了一下奇数的个数,来算最少的步骤,结果在第4个点就WA了,然后改正之后,又是少特判的0这个东西。当所有的数都为0时,是不可能达成最大公约数大于1的情况的。最后改正过来后成功AC。不过还需注意的是负数和正数的最大公因数,只需要吧这个负数当成正数看就行了。

给出题解:
#include<bits/stdc++.h>using namespace std;int get_gcd(int a,int b){    if(a!=0&&b!=0)    {        a=abs(a);        b=abs(b);        int m=min(a,b);    for(int i=m;i>=1;i--)    if(a%i==0&&b%i==0)return i;    }    if(a==0||b==0)return max(a,b);}int main(){    bool flag=false;    int n,cnt=0,gcd,ans=0,t;    int a[100010];    cin>>n;    for(int i=1;i<=n;i++)    {        cin>>a[i];        if(a[i]!=0)flag=true;    }    if(flag==true)    {        for(int i=2;i<=n;i++)        {        if(i==2)gcd=get_gcd(a[1],a[i]);        else gcd=get_gcd(gcd,a[i]);        }        if(gcd!=1)cout<<"YES"<<endl<<0;        else         {            for(int i=1;i<n;i++)            if(a[i]%2==1&&a[i+1]%2==1)            {            cnt++;            t=a[i];            a[i]=t-a[i+1];            a[i+1]=t+a[i+1];            }            for(int i=1;i<n;i++)            {            if(a[i]%2==0&&a[i+1]%2==1)            {                cnt=cnt+2;            t=a[i];            a[i]=t-a[i+1];            a[i+1]=t+a[i+1];            t=a[i];            a[i]=t-a[i+1];            a[i+1]=t+a[i+1];            }            else if(a[i]%2==1&&a[i+1]%2==0)            {                cnt=cnt+2;            t=a[i];            a[i]=t-a[i+1];            a[i+1]=t+a[i+1];            t=a[i];            a[i]=t-a[i+1];            a[i+1]=t+a[i+1];            }            }        cout<<"YES"<<endl<<cnt;        }    }    else cout<<"NO";return 0;}

蒻蒟总结:

今天的群赛感觉有思路的题都能够A掉,但剩余的两题在比赛时感觉比较难,订正时也比较吃力,正在极力的订正中,所以第3、5题就先不发题解了,下一次发博客的时候再补回来。这两题都是我不怎么擅长的深搜,建树等等的,所以一旦有时间,就抓紧去补吧。


原创粉丝点击