Coder-Strike 2014 - Finals (online edition, Div. 1)-a-b-c

好久没写博客了,因为最近也没做到啥有价值的题目。昨天做了一场CF,感觉题目还不错。。

A题:水题不多说了。。

B题:

这道题目的本质就是求谁有可能在所有的时间段都在开会。

那么我们就可以假设一开始所有的人都在开会。

在已知的这段时间段内,我们可以判断出每个人在会议的时间段的长度。

然后我们再求出这段时间段内所有有人的时间长度。

如果某个人在会议的时间长度等于所有的人在会议的时间长度的话,那么说明这个人有可能是领导。

vec[i]:i人出现在会议的时间段。

hh[i]:所有的人出现在会议的时间段。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<string>
using namespace std;
#define LL long long
int maps[201];
#define maxn 110000
struct list
{
    int s;
    int x;
    int leap;
}sig[maxn];
struct listt
{
    int st;
    int ed;
}tt,peo[maxn];
vector<listt>vec[maxn];
vector<listt>hh;
int f[maxn*3];
int cmp(struct listt a,struct listt b)
{
    return a.st<b.st;
}
void dos()
{
    memset(f,0,sizeof(f));
    sort(hh.begin(),hh.end(),cmp);
    int st,ed;
    st=ed=-1;
    int i,j;
    for(i=0;i<hh.size();i++)
    {
        if(hh[i].st>st)st=hh[i].st;
        if(hh[i].st<ed)st=ed+1;
        if(hh[i].ed>ed)ed=hh[i].ed;
        for(j=st;j<=ed;j++)f[j]=1;
    }
}
int main()
{
    int len,i,j;
    int n,m;
    char ch;
    int x;
    while(~scanf("%d%d%*c",&n,&m))
    {
        for(i=1;i<=n;i++)
        {
            vec[i].clear();
        }
        for(i=1;i<=m;i++)
        {
            scanf("%c %d%*c",&ch,&x);
            if(ch=='+')sig[i].s=1;
            else sig[i].s=0;
            sig[i].x=x;
        }
        for(i=1;i<=n;i++)
        {
            peo[i].st=1;
            peo[i].ed=-1;
        }
        hh.clear();
        int pp[maxn];
        for(i=1;i<=m;i++)
        {
            int a=sig[i].x;
            if(sig[i].s==1)
            {
                peo[a].st=2*i;
            }
            else
            {
                peo[a].ed=2*i;
                hh.push_back(peo[a]);
                vec[a].push_back(peo[a]);
            }
        }
        for(i=1;i<=n;i++)
        {
            if(peo[i].st==1)continue;
            if(peo[i].st>peo[i].ed)
            {
                peo[i].ed=2*(m+1);
                hh.push_back(peo[i]);
                vec[i].push_back(peo[i]);
            }
        }
        dos();
        vector<int>ans;
        ans.clear();
        int res=0;
        for(i=0;i<=m*2+10;i++)if(f[i])res++;
        for(i=1;i<=n;i++)
        {
            if(vec[i].size()==0)ans.push_back(i);
            else
            {
                int as=0;
                for(j=0;j<vec[i].size();j++)
                {
                    int st=vec[i][j].st;
                    int ed=vec[i][j].ed;
                    as+=ed-st+1;
                }
                if(as==res)ans.push_back(i);
            }
        }
        cout<<ans.size()<<endl;
        for(i=0;i<ans.size();i++)
        {
            cout<<ans[i];
            if(i!=(ans.size()-1))cout<<" ";
            else cout<<endl;
        }
    }
    return 0;
}

C题:

说到C题,心里尤其的伤心。。。

学校的网昨天不知道怎么抽了,打开个网页都得2分钟。。。

假如我们把每个人都看成一个点。

如果某个人说x,y是嫌疑犯,我们就把x,y两点之间联线。

这样,问题就转化成让我们从图中取出两个点,使得这两个点连到的边的个数大于等于p;

问有几种取法。

我们可以先算出所有点的度。

枚举每个点,看有几个点的度加上这个点的度大于等于p;

可以二分找。

然后在删掉一些非法的点对。

1,两个点一样。即如果点x的度乘以2大于等于p的话,结果--;

2,两个点的度的和虽然大于等于p,但是这两个点有重边。

还有一些要注意的情况:

1,结果有可能超INT,注意用long long;

2,题目输入的边(x,y)有可能y>x;

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<string>
using namespace std;
#define LL long long
int maps[201];
#define maxn 1100000
struct list
{
    int a;
    int b;
}edge[maxn],p;
int cmp(struct list a,struct list b)
{
    if(a.a!=b.a)return a.a<b.a;
    return a.b<b.b;
}
LL f[maxn];
LL num[maxn];
LL n,m;
int sea(int x)
{
    int l=1;
    int r=n+1;
    int mid=(l+r)/2;
    while(l<r)
    {
        if(f[mid]<x)l=mid+1;
        else r=mid;
        mid=(l+r)/2;
    }
    return mid;
}
int main()
{
    int len,i,j;
    char ch;
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        int x,y;
        for(i=1;i<=n;i++)f[i]=num[i]=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            a=min(x,y);
            b=max(x,y);
            edge[i].a=a;
            edge[i].b=b;
            f[a]++;
            f[b]++;
            num[a]++;
            num[b]++;
        }
        sort(f+1,f+n+1);
        sort(edge+1,edge+n+1,cmp);
        LL ans;
        ans=0;
        for(i=1;i<=n;i++)
        {
            LL x=num[i];
            LL y=m-num[i];
            LL w=sea(y);
            LL ns=n-w+1;
            if(x>=y)ns--;
            ans+=ns;
        }
      // cout<<"_-"<<ans<<endl;
        ans=ans/2;
        int leap=1;
        p=edge[1];
        for(i=2;i<=n+1;i++)
        {
            if(edge[i].a==edge[i-1].a&&edge[i].b==edge[i-1].b)leap++;
            else
            {
                a=p.a;
                b=p.b;
               // cout<<num[a]<<"-"<<num[b]<<" "<<leap<<endl;
                if(((num[a]+num[b]-leap)<m)&&((num[a]+num[b])>=m))ans--;
                leap=1;
                p=edge[i];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值