Codeforces Round #403 div2 题解
传送门:HustOJ
CodeForces 782A Andryusha and Socks
题意
太水了。。。暴力扫一遍,开个数组记一下就行了。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
int vis[MAXN];
int main()
{
_;
int n;
while(cin>>n)
{
int maxnum=0, curnum=0;
M(vis, 0);
for(int i=0;i<2*n;i++)
{
int a;cin>>a;
if(vis[a]==0)
{
curnum++;
vis[a]=1;
maxnum=max(curnum, maxnum);
}
else
{
curnum--;
vis[a]=0;
}
}
cout<<maxnum<<endl;
}
return 0;
}
CodeForces 782B The Meeting Place Cannot Be Changed
题意
一条路,上面有许多人,给你每个人的坐标和max速度。人可以以不超过max的速度在路上向NS两侧走。求一个最小时间,使得所有人在同一点碰面。
注意二分时要用次数二分,double会有精度问题。
思路
二分枚举时间,因为知道了时间就可以知道某人所能到达的范围。判定条件是所有人区间有交集。当所有人区间交于一点时是最优解。
代码
cout会有精度控制问题,不会控制精度,所以改成了printf
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
double pos[MAXN];
double v[MAXN];
bool check(int n,double m)
{
double l=-oo, r=oo;
for(int i=0;i<n;i++)
{
l=max(l, pos[i]-m*v[i]);
r=min(r, pos[i]+m*v[i]);
if(l-r>0) return false;
}
return true;
}
int main()
{
//_;
int n;
while(cin>>n)
{
M(pos, 0);M(v, 0);
for(int i=0;i<n;i++)
cin>>pos[i];
for(int i=0;i<n;i++)
cin>>v[i];
double ll=0, rr=oo;
int time=1000;
while(time--)
{
double mid=(ll+rr)/2.0;
if(check(n, mid))
rr=mid;
else
ll=mid;
}
printf("%.12lf\n", ll);
}
return 0;
}
CodeForces 782C Andryusha and Colored Balloons
题意
给你个n点,n-1边的连通图,染色。任意相邻三点不能同色,求染色数和染色结果。
思路
因为题给的图有 n 个点和 n−1 条边,并且这个图是连通图,所以这个图实际上是一棵树。
假设某个点 u 的父亲节点是 p (我们可以指定一个节点作为根节点),其子节点为 v 和 w ,那么显然 v 和 w 的颜色不能相同,不仅如此,它们俩的颜色还不能 u 相同或者与 p 相同(若这些条件不满足则三个连续的点就会出现颜色相同的点)。另外我们需要让颜色的总数最少。
所以从树根开始搜索( DFS ),为当前访问的点 u 的儿子们从颜色 1 开始染色(可以保证总颜色数最小),如果不出意外对于点 u 的儿子的染色结果应该是 1,2,3,…,number_of_son 。但是由于 u 的儿子 v 的颜色 color[v] 须与 u,p 不同,所以遇到 color[u] 和 color[p] 这两种颜色就跳过。当访问完所有节点时,最大的节点的颜色编号就是答案。
因为n点n-1边的连通图,就是个树。
染色数就是最大度的点度数加1。至于染色dfs下去就好,一个点不能跟他的兄弟节点同色,不能跟他的祖父同色。
每对一个点的儿子们染色时,从颜色1开始染,如果遇到跟父亲以及祖父一样的颜色就跳过就行了。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=200005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
vector<int> G[MAXN];
int color[MAXN];
int mcol=0;
void dfs(int n, int fa)
{
int col=1;
for(int i=0;i<G[n].size();i++)
{
if(G[n][i]==fa) continue;
if(col==color[n]||col==color[fa]) col++;
if(col==color[n]||col==color[fa]) col++;
mcol=max(mcol, col);
color[G[n][i]]=col++;
dfs(G[n][i], n);
}
}
int main()
{
_;
int n;
while(cin>>n)
{
mcol=0;
for(int i=1;i<n;i++)
{
int a, b;cin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
color[0]=0;color[1]=1;
dfs(1, 0);
cout<<mcol<<endl;
for(int i=1;i<=n;i++)
cout<<color[i]<<(i==n ? '\n' : ' ');
}
return 0;
}
CodeForces 782D Innokenty and a Football League
题意
一堆足球队,每个队名字有两个单词,每个单词长于3个字母。现在要取简称,所有人简称不能一样。简称有两种取法,取第一个词的前三个字母或者第一个词的前两个字母加第二个词的第一个字母。
不过,有些队的第一种简称相同,对于这样的队们,他们全部必须用第二种简称。
建议读原题。
思路
反正C++有STL,而且数据量不大,map set随便搞。。
不过注意一下这个样例,我和cbox都在这gg了。应该是CF的test16
4
ABH OPQ
ABH POQ
ABC DEF
ABO CDE
如果你输出NO,那么再仔细看一下,会明白的。
我的解决方案是,用map统计第一种简称重名的,记录下来。然后先搞那些第一种简称重名的队伍(统称W),他们没选择,只能用第二种简称。
接下来扫那些第一种简称唯一的队伍,他们中有的队的第一种简称会被占用W中的队伍占用。这时候扫的时候,如果一个队只剩一种简称可用,那么就用,出现冲突就NO。如果一个队两种简称都可用,那么先不管他,直到剩下的所有的队都是两种简称都可用的时候,这时候他们之间应该是用哪种简称都彼此不冲突的(没证明,只是感觉),这时候在处理他们。
感觉我说的不清晰就看代码吧,这种东西每个人处理方法不一样,只要知道是什么问题就行了。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=200005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
map<string, vector<int> > mp;
struct Name
{
string full1;
string full2;
string nick;
Name(){}
Name(string _a, string _b, string _c) { full1=_a;full2=_b;nick=_c; }
};
vector<Name> vec;
set<string> se;
int main()
{
_;
int n;
while(cin>>n)
{
int nn=n;
for(int i=0;i<n;i++)
{
string a, b;cin>>a>>b;
vec.push_back(Name(a, b, ""));
string tt=a.substr(0, 3);
mp[tt].push_back(i);
}
map<string, vector<int> >::iterator ite;
bool flag=0;
for(ite=mp.begin();ite!=mp.end();ite++)
{
if(ite->second.size()!=1)
{
for(int i=0;i<ite->second.size();i++)
{
int num=(ite->second)[i];
string ne=vec[num].full1.substr(0, 2)+vec[num].full2.substr(0, 1);
if(se.count(ne)!=0) { flag=1;break; }
else { se.insert(ne);vec[num].nick=ne;nn--; }
}
}
if(flag==1) break;
}
bool ook=0;
while(flag!=1&&nn>0)
{
bool ok=0;
for(int i=0;i<n;i++)
{
if(vec[i].nick=="")
{
string res1=vec[i].full1.substr(0, 3);
string res2=vec[i].full1.substr(0, 2)+vec[i].full2.substr(0, 1);
if(se.count(res1)==0&&se.count(res2)==0)
{
if(ook==0) continue;
else
{
vec[i].nick=res1;
se.insert(res1);
nn--;
}
}
else if(se.count(res1)==0)
{
vec[i].nick=res1;
se.insert(res1);
ok=1;
nn--;
}
else if(se.count(res2)==0)
{
vec[i].nick=res2;
se.insert(res2);
ok=1;
nn--;
}
else
{
flag=1;
break;
}
}
}
if(ok==0) ook=1;
}
if(flag==1) cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(int i=0;i<vec.size();i++)
{
cout<<vec[i].nick<<endl;
}
}
}
return 0;
}
CodeForces 782E Underground Lab
题意
给你一个连通五向图,k个人,你要给他们分配路径,使得图中每个点都被访问过至少一次。
思路
我不太会,参考了很多人的。。。首先每个人不能走超过2n/k个节点,但是dfs序遍历以后最多会得到2n个节点,所以dfs序遍历一下,然后给k个人划分一下路径就好。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=200005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
vector<int> G[MAXN];
vector<int> dfsres;
bool vis[MAXN];
int dfsnum=0;
void dfs(int n, int fa)
{
vis[n]=1;
dfsres.push_back(n);
for(int i=0;i<G[n].size();i++)
{
if(!vis[G[n][i]])
{
dfs(G[n][i], n);
dfsres.push_back(n);
}
}
}
int main()
{
_;
int n;
while(cin>>n)
{
int m, k;cin>>m>>k;
for(int i=0;i<m;i++)
{
int a, b;cin>>a>>b;
G[a].push_back(b);G[b].push_back(a);
}
M(vis, 0);
dfs(1, 0);
int sum=dfsres.size();
int now=0;
int pep=2*n/k;
if(pep*k!=2*n) pep++;
for(int i=0;i<k;i++)
{
if(now>=sum)
{
cout<<"1 1"<<endl;
}
else
{
int ou=min(pep, sum-now);
cout<<ou<<endl;
ou=now+ou;
for(;now<ou;now++)
{
cout<<dfsres[now]<<(now==ou-1 ? '\n' : ' ');
}
}
}
}
return 0;
}