地址:http://codeforces.com/contest/274
解题报告 http://codeforces.com/blog/entry/6759
赛后补完后都忘了总结。。。。。
A:找出一个最大的集合,使得不存在一个数是另一个数的k倍,将矛盾的数之间建边,会有很多条单链,可知有一半的数可以一起存在
http://codeforces.com/contest/274/submission/3166962
B:给你一棵树,每个点的权值有正有负,现在让你用最少的操作次数 , 让整棵树的权值为零。
一次操作是这样的: 一次只能给一个联通子集 +1 或 -1,这个连通子集必须要包括1这个点。
显然,以1为根,自底向上来做,把当前点变成0,父亲节点必须要做一样的操作,然后一直到根就可以了。
http://codeforces.com/contest/274/submission/3167398
C:有一百个圆心,每个圆不断的膨胀,最后变成一体,判断最后一个点消失的时间。
只有锐角三角形才需要判断,所以算法是n^3暴力枚举每个三角形,不过还需要判断两个直角三角形组成一个矩形的特殊情况
#include <math.h> #include <cstdio> #include <map> #include <algorithm> using namespace std; const double eps = 1e-5; struct point{double x,y;}; struct line{point a,b;}; point p[110],cen; int n ; double ans ; double dis(point p1,point p2){ return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y); } point intersection(line u,line v){ point ret=u.a; double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x)) /((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x)); ret.x+=(u.b.x-u.a.x)*t; ret.y+=(u.b.y-u.a.y)*t; return ret; } //外心 point circumcenter(point a,point b,point c){ line u,v; u.a.x=(a.x+b.x)/2; u.a.y=(a.y+b.y)/2; u.b.x=u.a.x-a.y+b.y; u.b.y=u.a.y+a.x-b.x; v.a.x=(a.x+c.x)/2; v.a.y=(a.y+c.y)/2; v.b.x=v.a.x-a.y+c.y; v.b.y=v.a.y+a.x-c.x; return intersection(u,v); } void Init() { scanf("%d",&n); for(int i =0 ; i < n ; i++) scanf("%lf%lf",&p[i].x,&p[i].y); } void judge(int i,int j,int k,double dx) { bool f = true; for(int kk = 0; kk < n; kk++){ if(kk!=i && kk!=j && kk!=k) { double dd = dis(cen,p[kk]) ; if(dd - dx < -eps) { f = false; break;} } } if(f) ans = max(ans,dx); } void Gao() { ans = -1; for(int i = 0; i < n; i++) for(int j = i+1; j < n; j++) for(int k = j+1; k < n; k++) { double d[3]; d[0] = dis(p[i],p[j]); d[1] = dis(p[i],p[k]); d[2] = dis(p[j],p[k]); if(d[0] == d[1] + d[2]) { int aim = -1; for(int l = 0; l < n; l++) { if(l == i || l==j || l==k) continue; double d1 = dis(p[i],p[l]); double d2 = dis(p[j],p[l]); if(d[0] == d1 + d2) aim = l; } if(aim!=-1) //长方形 { cen.x = (p[i].x+p[j].x) / 2; cen.y = (p[i].y+p[j].y) / 2; double dx = dis(cen,p[i]); judge(i,j,k,dx); } } sort(d,d+3); if(d[0]+d[1] <= d[2]) continue; cen = circumcenter(p[i],p[j],p[k]); double dx = dis(cen,p[i]); judge(i,j,k,dx); } if(ans != -1) printf("%lf",sqrt(ans)); else puts("-1"); } int main(){ Init(); Gao(); return 0; }
D:给你一个n*m的矩阵,问你是否存在一种方案,使得重新摆放每列的位置之后每行的元素是非递减的。
很容易想到一个拓扑模型,不过要建的边太多了貌似,方法是建一些虚拟节点。具体见这里
以下自然段转自http://blog.csdn.net/zucc_dianbei/article/details/8600058
把列之间的关系转化为图进行拓扑排序是很容易想到的一个突破口,关键在于如何建图。举一个只有一行的例子:1,2,3,4,5。点1比其他点都小,所以点1向其他4点各连一条边,点2往3,4,5连边,依次类推。。。这样正确但边数太多了。对于这个例子可以这样建图1->2->3->4->5 (每个点只向最小的比其大的点连边),边的数量大大减少。但如果是1,1,1,2,2,2这种数据又行不通了,所有的1都要向每个2连边,边的数量还是平方级别的。这里我们可以用添加虚拟节点的方法来解决,对于第2个例子,增加3个虚拟节点v1,v2,v3,v1向所有1连边,所有1向v2连边,v2向所有2连边,所有2向v3连边。这种方法保证边的数量是O(n*m)的
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct node {
int num , id;
bool operator < (const node&cmp) const {
return num < cmp.num;
}
}in[maxn];
vector<int> edge[maxn*2];
int ind[maxn*2];
int main()
{
int n , m , k = 0;
cin >> n >> m;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
cin>>in[j].num;
in[j].id = j;
}
sort(in,in+m);
for(int j= 0; j < m; j++) if(in[j].num!=-1)
{
if(j==0 || in[j].num!=in[j-1].num) k++;
edge[in[j].id].push_back(m+k);
edge[m+k-1].push_back(in[j].id);
}
k++;
}
for(int i = 0; i < m+k; i++) for(int j = 0; j < edge[i].size(); j++) ++ind[edge[i][j]];
queue<int> Q; vector<int> ans;
for(int i = 0; i < m+k; i++) if(ind[i]==0) Q.push(i);
while(!Q.empty())
{
int fr = Q.front(); Q.pop();
if(fr < m) ans.push_back(fr);
for(int i=0;i<edge[fr].size();i++) if((--ind[edge[fr][i]])==0) Q.push(edge[fr][i]);
}
if(ans.size()==m)
{
for(int i = 0; i < ans.size(); i++) cout<<ans[i]+1<<" ";
}
else cout<<"-1";
return 0;
}
E题:可以将所有的斜条分类,\ 这种斜条的x-y是相等的,/ 这种斜条的x+y是相等的,所有就可以根据这个值将所有的障碍方格离散出来,每次发射的时候二分查找会碰到哪一个障碍格子,还有一个性质就是一个方格只会一一种方向进入,可以根据奇偶性来证明,\ / 这两种“斜”法是不可能进去同一个格子的,因为奇偶性不同,所以就不用担心某个格子会被这样经过两次,具体实现的细节需要想清楚。
#include <cstdio> #include <cstring> #include <set> #include <string> #include <iostream> #include <cmath> #include <vector> #include <cstdlib> #include <algorithm> using namespace std; typedef pair<int,int> pii; #define sqr(x) ((x)*(x)) #define PB push_back #define MP make_pair #define ins insert #define X first #define Y second set<pii>::iterator it; #define Tr(it, x) for(it = x.begin(); it!=x.end();it++) #define SZ(x) x.size() #define SORT(x) sort(x.begin(),x.end()) #define REP(i,n) for(int i=0;i<n;i++) const int maxn = 200010; const int mod = 1000000007; vector<pii> dag1[maxn],dag2[maxn]; set<pii> Point; int n , m , sx ,sy; long long ans ; /* 0 3 2 1 */ pii get_val(int x,int y) { return MP(y-x+n+1,x+y); } bool judge(int x,int y,int dir) { return ( (x+y == sx+sy) &&(dir==2||dir==3) || (x-y == sx-sy) && (dir==0||dir==1)) ; } int mp1[] = {3,2,1,0}; int mp2[] = {2,3,0,1}; int cnt; void go(int x,int y,int dir) { pii val = get_val(x,y); vector<pii> to; vector<pii>::iterator it; to = dir < 2 ? dag1[val.X] : dag2[val.Y]; it = lower_bound(to.begin(),to.end(),MP(x,y)); if(dir == 3) --it; if(dir == 0) --it; if(judge(x,y,dir)) if(sx > min(it->X,x) && sx < max(it->X,x)) { ans += abs(sx - x); return ; } ans += abs(it->X-x); int dx = x < it->X ? -1 : 1; int dy = y < it->Y ? -1 : 1; pii t1 = MP(it->X + dx , it->Y); pii t2 = MP(it->X, it->Y + dy); bool flag1 = (Point.find(t1)!=Point.end()); bool flag2 = (Point.find(t2)!=Point.end()); if(flag1 == flag2) { x = it->X + dx; y = it->Y + dy; dir ^= 1; } else if(flag1){ x = t2.X; y = t2.Y; dir = mp1[dir] ; } else{ x = t1.X; y = t1.Y; dir = mp2[dir]; } if(MP(x,y)==MP(sx,sy)) return ; go(x,y,dir); } int main() { int k , x , y , sdir; cin >> n >> m >> k; REP(i,k) { scanf("%d%d",&x,&y); Point.ins(MP(x,y)); } REP(i,n+2) Point.ins(MP(i,0)),Point.ins(MP(i,m+1)); REP(i,m+2) Point.ins(MP(0,i)),Point.ins(MP(n+1,i)); Tr(it,Point) { pii val = get_val(it->X,it->Y); dag1[val.X].PB(*it); dag2[val.Y].PB(*it); } REP(i,n+m+3) SORT(dag1[i]),SORT(dag2[i]); string s; scanf("%d%d",&sx,&sy); cin>>s; if(s == "NE") sdir = 3; else if(s == "NW") sdir = 0; else if(s == "SE") sdir = 1; else sdir = 2; go(sx,sy,sdir); go(sx,sy,sdir^1); printf("%I64d\n",ans/2); return 0; }