记录编号 244467 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [国家集训队2011]新家 最终得分 100
用户昵称 Gravatarmikumikumi 是否通过 通过
代码语言 C++ 运行时间 1.802 s
提交时间 2016-04-01 08:23:40 内存使用 0.37 MiB
显示代码纯文本
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int SIZEN=1010;
typedef long long LL;
int N;
class poi
{
public:
	int x,y;
}P[SIZEN];
int gcd(int x,int y)
{
	if(!y) return x;
	return gcd(y,x%y);
}
class miku//线
{
public:
	int x1,y1,x2,y2;
	LL a,b,c;//直线方程
	bool flag;//斜率
	void push(poi g,poi f)
	{
		x1=g.x,y1=g.y,x2=f.x,y2=f.y;
		if(x1>x2) {swap(x1,x2);swap(y1,y2);}
		LL A=y2-y1,B=x2-x1;
		LL C=gcd(A,B);
		A/=C;B/=C;
		if(B<0) A*=(-1),B*=(-1);
		a=A;c=B;b=B*y1-A*x1;
		if(y1>y2) flag=1;
		else flag=0;
	}
	void print()
	{
		cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
		cout<<"a:"<<a<<" "<<"b:"<<b<<" "<<"c:"<<c<<endl;
		cout<<endl;
	}
}L[SIZEN];
int key[SIZEN];
void read()
{
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
		scanf("%d%d",&P[i].x,&P[i].y),key[i]=P[i].x;
}
void prepare()
{
	for(int i=1;i<N;i++) 
		L[i].push(P[i],P[i+1]);
	L[N].push(P[N],P[1]);
	//for(int i=1;i<=N;i++) L[i].print();
}
pair<double,int> S[SIZEN*2];
bool cmp(miku a,miku b,int x1,int x2)
{
	LL A=(a.a*x1+a.b)/a.c;
	LL B=(b.a*x2+b.b)/b.c;
	if(A<=B) return 1;
	if(A>B+1) return 0;
	A=(a.a*x1+a.b)%a.c;
	B=(b.a*x2+b.b)%b.c;
	return (A*b.c-B*a.c)<0;
}
LL get(LL a,LL b,LL c,LL n)
{
	if(a<0) return get(-a,b+a*(n-1),c,n);
	if(!n) return 0;
	LL re=0;
	if(a>=c) re+=n*(n-1)/2*(a/c),a%=c;
	if(abs(b)>=c) re+=n*(b/c),b%=c;
	if(!a) return re;
	re+=get(c,(a*n+b)%c,a,(a*n+b)/c);
	return re;
}
LL get1(miku a,int x1,int x2)//向下取整
{
	LL re=get(a.a,a.b,a.c,x2+1);
	re-=get(a.a,a.b,a.c,x1);
	return re;
}
LL get2(miku a,int x1,int x2)//向上取整
{
	LL re=get(a.a,a.b+a.c-1,a.c,x2+1);
	re-=get(a.a,a.b+a.c-1,a.c,x1);
	return re;
}
LL Calc(miku a,miku b,int x1,int x2)//处理在直线a下,直线b上,横坐标在x1,x2之间的格子
{
	//将a上所有的点的y坐标向下取整,减去b上所有点的y坐标向上取整的结果,便是答案
	//由于a上的点是向下取整,b上的点事向上取整,所以会出现floor<ceil的情况
	//我们需要二分出来一个x,使得floor>=ceil
	if(cmp(a,b,x1+a.flag,x1+!b.flag))
	{
		int l=x1,r=x2;
		while(l<r)
		{
			int mid=(l+r)/2;
			if(cmp(a,b,mid+a.flag,mid+!b.flag)) l=mid+1;
			else r=mid;
		}
		x1=r;
		if(x1>x2) return 0;
	}
	if(cmp(a,b,x2-!a.flag,x2-b.flag))
	{
		int l=x1,r=x2;
		while(l+1<r)
		{
			int mid=(l+r)/2;
			if(cmp(a,b,mid-!a.flag,mid-b.flag)) r=mid;
			else l=mid;
		}
		x2=l;
		if(x1>x2) return 0;
	}
	LL re=0;
	if(!a.flag) re+=get1(a,x1,x2-1);
	else re+=get1(a,x1+1,x2);
	if(!b.flag) re-=get2(b,x1+1,x2);
	else re-=get2(b,x1,x2-1);
	return re;
}
void work()
{
	sort(key+1,key+1+N);//离散化x坐标
    LL ans=0;
	for(int i=1;i<N;i++)
	{
		if(key[i+1]==key[i]) continue;
		int tot=0;
		for(int j=1;j<=N;j++)
		{
			if(L[j].x1<=key[i]&&L[j].x2>=key[i+1])
				S[++tot]=make_pair((double)(L[j].a*(double)(key[i+1]+key[i])/2.0+L[j].b)/L[j].c,j);
		}
		sort(S+1,S+1+tot);
		for(int j=1;j<=tot;j+=2)
		{
			LL tem=Calc(L[S[j+1].second],L[S[j].second],key[i],key[i+1]);
			ans+=tem;		
		}
	}
	printf("%lld\n",ans);
}
int main()
{
	freopen("nt2011_zej_c.in","r",stdin);
	freopen("nt2011_zej_c.out","w",stdout);
	read();
	prepare();
	work();
	return 0;
}