当前位置: 代码迷 >> 综合 >> Coder-Strike 2014 - Finals (online edition, Div. 1)-a-b-c
  详细解决方案

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

热度:77   发布时间:2023-12-19 10:42:35.0

好久没写博客了,因为最近也没做到啥有价值的题目。昨天做了一场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;
}















  相关解决方案