czl蒻蒟的OI之路2

—>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 100010
using 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题就先不发题解了,下一次发博客的时候再补回来。这两题都是我不怎么擅长的深搜,建树等等的,所以一旦有时间,就抓紧去补吧。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值