CF372E Drawing Circles is Fun(圆反演,组合计数)

题目
题意:
平面内 n n n个点,其中任意两点所在的直线上都不包含原点。
求一种集合的个数: ( P 1 , P 2 ) ( P 3 , P 4 ) . . . ( P 2 k − 1 , P 2 k ) (P_1,P_2)(P_3,P_4)...(P_{2k-1},P_{2k}) (P1,P2)(P3,P4)...(P2k1,P2k)使得:
1.不存在 i ! = j , P i = P j i != j , P_i=P_j i!=j,Pi=Pj.
2.不存在一对 i ! = j , ( P 2 i − 1 , P 2 i ) ( P 2 j − 1 , P 2 j ) i!=j,(P_{2i-1},P_{2i})(P_{2j-1},P_{2j}) i!=j,(P2i1,P2i)(P2j1,P2j)满足,圆 O P 2 i − 1 P 2 j − 1 OP_{2i-1}P_{2j-1} OP2i1P2j1和圆 O P 2 i P 2 j OP_{2i}P_{2j} OP2iP2j只有一个交点,圆 O P 2 i − 1 P 2 j OP_{2i-1}P_{2j} OP2i1P2j和圆 O P 2 i P 2 j − 1 OP_{2i}P_{2j-1} OP2iP2j1只有一个交点。

n < = 1000 n<=1000 n<=1000

圆反演之后可以推出对于 ( P 2 i − 1 , P 2 i ) ( P 2 j − 1 , P 2 j ) (P_{2i-1},P_{2i})(P_{2j-1},P_{2j}) (P2i1,P2i)(P2j1,P2j)需要满足 ( P 2 i − 1 , P 2 i ) (P_{2i-1},P_{2i}) (P2i1,P2i) ( P 2 j − 1 , P 2 j ) (P_{2j-1},P_{2j}) (P2j1,P2j)构成了平行四边形并且 P 2 i − 1 P_{2i-1} P2i1 P 2 i P_{2i} P2i是不相邻的顶点。
所以就是互相平分,求线段的中点然后统计一下就可以了。

A C   C o d e \rm AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 600005
#define LL long long
using namespace std;

int n,m,w,a[maxn],b[maxn],c[maxn],idc[maxn],pdc[maxn],pda[maxn],ida[maxn],tg[maxn],mx[maxn];
bool cmp1(const int &u,const int &v){ return c[u] < c[v]; }
bool cmp2(const int &u,const int &v){ return b[u] < b[v]; }

int main(){
	scanf("%d%d",&n,&w);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i],&b[i]);
		if(b[i] - a[i] >= a[i]){
			c[++c[0]] = a[i] , pdc[c[0]] = i;
			c[++c[0]] = b[i] - a[i] , pdc[c[0]] = i;
		}
		else{
			pda[++m] = i;
			a[m] = a[i] , b[m] = b[i];
		}
	}
	for(int i=1;i<=c[0];i++) idc[i] = i;
	for(int i=1;i<=m;i++) ida[i] = i;
	sort(idc+1,idc+1+c[0],cmp1);
	sort(ida+1,ida+1+m,cmp2);
	LL ans = 0x3f3f3f3f3f3f3f3fll , lc = 0 , la = 0 , lm = 0 , lq = 0 , sum = 0 , mxa = 0 , j = m;
	for(int i=1;i<=m;i++){
		sum += b[i];
		if(i == 1) mx[i] = ida[1];
		else mx[i] = b[ida[i]]-a[ida[i]] > b[mx[i-1]] - a[mx[i-1]] ? ida[i] : mx[i-1];
	}
	for(int i=0;i<=c[0];i++){
		for(;j>=0 && j*2+i > w;j--){
			sum -= b[ida[j]];
			if(mxa == 0 ||  a[ida[j]] < a[mxa]) mxa = ida[j];
		}
		if(j < 0) break;
		if(j * 2 + i == w){
			if(sum < ans)
				ans = sum , lc = i , la = j , lm = 0 , lq = 0;
		}
		else if(j*2+i+1 == w){
			if(mxa && sum + a[mxa] < ans){
				ans = sum + a[mxa] , lc = i , la = j , lm = mxa , lq = 0;
			}
			if(j < m && mx[j+1] && sum + b[ida[j+1]] - b[mx[j+1]] + a[mx[j+1]] < ans)
				ans = sum + b[ida[j+1]] - b[mx[j+1]] + a[mx[j+1]] , lc = i , la = j+1 , lm = 0 , lq = mx[j+1];
		}
		sum += c[idc[i+1]];
	}
	printf("%lld\n",ans);
	for(int i=1;i<=lc;i++) tg[pdc[idc[i]]]++;
	for(int i=1;i<=la;i++) tg[pda[ida[i]]] += 2;
	if(lm) tg[pda[lm]]++;
	if(lq) tg[pda[lq]]--;
	for(int i=1;i<=n;i++) printf("%d",tg[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值