Codeforces 698D

100 篇文章 0 订阅
5 篇文章 1 订阅

考虑枚举一个怪物 x x x能不能被石头 y y y射到,那么我们发现 x x x y y y之间连线上的其他怪物要先被干掉,继续搜索下去,但是胡乱爆搜的话很不可过。
有一个神秘的做法,我们给每个怪物枚举射过来的 k ! k! k!种排列,按bfs或dfs的顺序扩展要干掉的怪物,每搜到一个怪物的时候就钦定由排列对应位置上的石头射到它,如果扩展出来的石头数目不超过 k k k就合法。
这样为什么是对的呢?注意到如果存在一个合法的解,对它搜索的话一定会有某个扩展顺序,那么当枚举到那个扩展顺序对应的排列时就恰好有解了。
预处理的时候暴力即可,判定可以用叉积和点积看看。时间复杂度 O ( n 2 k + n k ! k ) \mathcal O(n^2k+nk!k) O(n2k+nk!k)

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
 
struct Point {
  ll x,y;
  Point() {}
  Point(ll a,ll b):x(a),y(b) {}
  Point operator - (Point b) {return Point(x-b.x,y-b.y);}
};
 
inline ll cross(Point x,Point y) {
  return x.x*y.y-x.y*y.x;
}
 
inline ll dot(Point x,Point y) {
  return x.x*y.x+x.y*y.y;
}
 
bool inside(Point x,Point y,Point z) {
  return !cross(x-z,y-z)&&dot(x-z,y-z)<0;
}
 
vector <int> vt[1005][10];
 
int vis[1005],vis_cnt;
int per[10];
 
int q[10];
 
bool bfs(int s,int k) {
  vis_cnt++;
  int l=1,r=0;
  q[++r]=s;vis[s]=vis_cnt;
  while (l<=r) {
  	int x=q[l],v=per[l];
  	l++;
  	for(int i=0;i<vt[x][v].size();i++)
  	  if (vis[vt[x][v][i]]<vis_cnt) {
  	  	  int u=vt[x][v][i];
  	  	  vis[u]=vis_cnt;
  	  	  q[++r]=u;
  	  	  if (r>k) return 0;
		}
  }
  return 1;
}
 
Point a[10],b[1005];
 
int main() {
  int k,n;
  scanf("%d%d",&k,&n);
  for(int i=1;i<=k;i++) {
  	int x,y;
  	scanf("%d%d",&x,&y);
  	a[i]=Point(x,y);
  }
  for(int i=1;i<=n;i++) {
  	int x,y;
  	scanf("%d%d",&x,&y);
  	b[i]=Point(x,y);
  }
  for(int i=1;i<=n;i++)
    for(int j=1;j<=k;j++)
      for(int l=1;l<=n;l++)
        if (inside(a[j],b[i],b[l])) vt[i][j].push_back(l);
  int ans=0;
  for(int i=1;i<=n;i++) {
  	bool ok=0;
  	for(int j=1;j<=k;j++) per[j]=j;
  	do {
  		if (bfs(i,k)) {
  			ok=1;
  			break;
		  }
	  } while (next_permutation(per+1,per+k+1));
	ans+=ok;
  }
  printf("%d\n",ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值