Codeforces Round #430 (Div. 2)

30 篇文章 0 订阅
13 篇文章 0 订阅

不知不觉,又好久没写blog了,双管齐下,不免有点精力不足,但相信自己,相信队友,全力以赴,胜利就在前方

 

成功组队后的第一次真正意义上的个人cf,有压力,但确实也过于疏忽

 

A. Kirill And The Game

 

思路:告诉你分子与分母区间,分子分母均为整数,再给你一个整数,问你是否在该区间内

小心翼翼,判断区间端点,考虑到整数,转成double,担心精度丢失,加个eps还resubmit一次,为此扣了50分,心疼半天

后来无聊,还锁了自己的题,美滋滋去hack别人

到头来都没想到,整数规划问题,不仅仅是边界上的陷阱,中间也有值的缺漏,当队友被fst的那一刻,看到队友的代码,瞬间感受到了自己同样的命运

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

int main()
{
    int l,r,x,y,k;
    while(scanf("%d%d%d%d%d",&l,&r,&x,&y,&k)!=EOF)
    {
        double mink = double(l) / double(y);
        double maxk = double(r) / double(x);
        //cout << maxk << " " << mink <<" " << k<< endl;
        if((maxk+1e-9)>=k&&(mink-1e-9)<=k)
        {
            int i;
            for(i=l;i<=r;i++)
            {
                if(i%k==0)
                {
                    printf("YES\n");
                    break;
                }
            }
            if(i<=r)
            {
                continue;
            }
        }
        printf("NO\n");
        /*bool ok = false;
        for(int i=l;i<=r;i++)
        {
            if(i%k==0&&x<=i/k&&y>=i/k)
            {
                ok = true;
                break;
            }
        }
        if(ok)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }*/
    }
    /*int l,r,x,y;
    double k;
    cin >> l >> r >> x >> y >> k;
    if(l/y<=k&&k<=r/x)
        cout<<"Y";
        else
        cout<<"N";*/
    return 0;
}

 

 

 


B. Gleb And Pizza

 

思路:或许这才是这次比赛最水的一题了吧,根据圆的性质,判断顶点距离关系即可

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

int main()
{
    int r,d;
    while(scanf("%d%d",&r,&d)!=EOF)
    {
        int n;
        scanf("%d",&n);
        int sum = 0;
        for(int i=0;i<n;i++)
        {
            int x,y,rr;
            scanf("%d%d%d",&x,&y,&rr);
            if(((x*x + y*y)>=(r-d+rr)*(r-d+rr))&&((x*x+y*y)<=(r-rr)*(r-rr)))
            {
                sum++;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

 

 

 

 

 

C. Ilya And The Tree

思路:找树上最大公约数,2e5的复杂度,O(n^2)的算法,本想到用最大公约数剪枝,将每点单独处理成已去点和未去点两类,但担心极端n个最大公约数,又是O(1e10)的复杂度,感觉会凉,殊不知,gcd具有下降性,且每次下降1/2,因此n个数的gcd最多只有log(n),set完美解决,因此,该算法复杂度实际为O(nlog(n))完全没问题

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5+10;

int a[maxn];

bool vis[maxn];

vector<int> ne[maxn];

int full[maxn];

set<int> nofull[maxn];

int gcd(int a,int b)
{
	return b == 0 ? a : gcd(b, a % b);
}

void dfs(int la,int p)
{
    //cout << "$$$" << p << "$$$"<<endl;
    vis[p] = true;
    full[p] = gcd(full[la],a[p]);
    set<int> :: iterator it;
    for(it = nofull[la].begin();it!=nofull[la].end();it++)
    {
        nofull[p].insert(gcd((*it),a[p]));
        //cout << "-" << (*it) <<"-" <<gcd((*it),a[p])<<"-"<<a[p] << "-" << endl;
    }
    nofull[p].insert(full[la]);
    //cout << "*-*-" << *(nofull[1].begin()) << endl;
    vector<int> :: iterator itne;
    for(itne = ne[p].begin();itne!=ne[p].end();itne++)
    {
        if(!vis[(*itne)])
        {
            dfs(p,(*itne));
        }
    }
    return ;
}

int main()
{
    int n;
    //cout << gcd(0,5) << endl;;
    while(scanf("%d",&n)!=EOF)
    {
        memset(vis,false,sizeof(vis));
        ne[0].clear();
        nofull[0].clear();
        full[0] = 0;
        ne[0].push_back(1);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            ne[i].clear();
            nofull[i].clear();
        }
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            ne[x].push_back(y);
            ne[y].push_back(x);
        }
        dfs(0,1);
        for(int i=1;i<n;i++)
        {
            //cout <<"**"<<*(nofull[i].begin())<<"*"<<*(nofull[i].rbegin()) << "***" << endl;
            printf("%d ",max((*(nofull[i].rbegin())),full[i]));
        }
        printf("%d\n",max((*(nofull[n].rbegin())),full[n]));
    }
    return 0;
}


最后给个访问set首尾元素的小tip:

 

set <template T> a; 首元素 = * ( a.begin()); 尾元素 = * (a.rbegin());


D. Vitya and Strange Lesson

思路:这题确实难度不小,O(3e5)的查询,每次长度为3e5的mex数组异或与查找,确实不易操作

总查询次数肯定是定死无法操作的,因此想到优化每次查询与异或操作,看能不能将线性降到log级

于是想到二分,由于异或操作是按位的,又想到按位操作,最多19位,O(19*log(3e5))的时间复杂度是相当可观的

考虑到最高位的异或,只会将最大与最小两部分交换,于是二分,一步步缩小查询区间还是比较可行的

至于mex值的所在区间,利用数字标记,累加,来判断是否缺值

来自分治dalao队友的想法,确实很妙

据说这题还可以用trie树来做,对于数据结构渣渣的我来说还是算了吧

 

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxt = 1e6+10;

int t[maxt];

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(t,0,sizeof(t));
        for(int i=0;i<n;i++)
        {
            int a;
            scanf("%d",&a);
            t[a] = 1;
        }
        for(int i=1;i<=maxt-10;i++)
        {
            t[i] += t[i-1];
        }
        int p = 0;
        while(m--)
        {
            int x;
            scanf("%d",&x);
            p ^= x;
            int st = 0;
            int fi = ((1<<19)-1);
            for(int pos = 18;pos >= 0;pos--)
            {
                int mid = (st + fi) >> 1;
                if(p & (1<<pos))
                {
                    int di = t[fi]-t[mid];
                    if(di<fi-mid)
                    {
                        st = mid + 1;
                    }
                    else
                    {
                        fi = mid;
                    }
                }
                else
                {
                    int di;
                    if(st>0)
                    {
                        di = t[mid] - t[st-1];
                    }
                    else
                    {
                        di = t[mid];
                    }
                    if(di<mid-st+1)
                    {
                        fi = mid;
                    }
                    else
                    {
                        st = mid+1;
                    }
                }
            }
            printf("%d\n",st^p);
        }
    }
    return 0;
}


明日第一场组队赛,加油,奋斗icpc/ccpc

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值