HDU 3571 N-dimensional Sphere(高斯消元 数论题)

这道题算是比较综合的了,要用到扩展欧几里得,乘法二分,高斯消元。

看了题解才做出来orz

基本思路是这样,建一个n*(n-1)的行列式,然后高斯消元。

关键就是在建行列式时会暴long long,所以要用取模来计算,即公式ax=b,等价于ax=b(mod p)

因为答案范围不超过正负10^17次,p可以取(2*10^17+3)。

然后加减乘除都能够进行了,乘法用乘法二分来做,除法用模线性方程求逆来做。

 

#include<stdio.h>

#include<math.h>

#include<algorithm>

using namespace std;

#define LL __int64

const LL p=(LL)200000000*1000000000+3;//杭电的编译器不能直接写200000000000000003,会ce

const LL L=(LL)100000000*1000000000;

LL ans[60],a[60][60],h[60][60];

int n;

LL modans(LL s)//取模

{

	if(s<0)

		s=s+p;

	else if(s>=p)

		s=s-p;

	return s;

}

LL calcu(LL base,LL tmp)//乘法二分

{

    LL ans=0;

	while(tmp)

	{

		if(tmp&1)ans=modans(ans+base);

		base=modans(base*2);

		tmp/=2;

	}

	return ans;

}

void get_h(int s)//每一行初始化

{

	int i,j;

	LL tmp=0;

	for(i=0;i<n;i++)

	{

		h[s][i]=modans(2*(a[s][i]-a[s+1][i]));

		tmp+=calcu(a[s][i],a[s][i])-calcu(a[s+1][i],a[s+1][i]);

		tmp=modans(tmp);

	    //printf("%I64d ",h[s][i]);

	}

	h[s][n]=tmp;

	//printf("%I64d\n",h[s][n]);

}

void init()

{

	int i,j;

	for(i=0;i<n;i++)

		get_h(i);

}

LL extEculid(LL a,LL b,LL &x,LL &y)

{

	LL tmp,d;

	if(b==0){x=1;y=0;return a;}

	d=extEculid(b,a%b,x,y);

	tmp=x;x=y;y=tmp-a/b*y;

	return d;

}

void solve()

{

	int i,j,k;

	for(i=0;i<n;i++)//这一步不能落下,当第i行第i个数是0时,要与下面的行互换。这题数据貌似有点水,要是互换后第i个数还是0,就会出错了。。。

	{

		for(j=0;j<n;j++)

			if(h[i][j])

				break;

		if(i<j)

		{

			for(k=0;k<=n;k++)

				swap(h[i][k],h[j][k]);

		}

	}

	for(i=0;i<n-1;i++)

	{

	  

	  for(j=i+1;j<n;j++)

	  {

		int tmp=h[i][j];

		for(k=i+1;k<=n;k++)

			h[j][k]=modans(calcu(h[j][k],h[i][i])-calcu(h[i][k],h[j][i]));

	  }

	}

	LL x,y,g;

	for(i=n-1;i>=0;i--)

	{

		g=extEculid(h[i][i],p,x,y);//由于p是质数,所以g实际上等于1

		ans[i]=calcu(x,h[i][n]);

		for(j=0;j<i;j++)

			h[j][n]=modans(h[j][n]-calcu(h[j][i],ans[i]));

	}

}

int main()

{

	int t,i,j;

	scanf("%d",&t);

	for(int k=1;k<=t;k++)

	{

		scanf("%d",&n);

		for(i=0;i<=n;i++)

		for(j=0;j<n;j++)

		{

			scanf("%I64d",&a[i][j]);

			a[i][j]+=L;

		}

                init();

		solve();

		printf("Case %d:\n",k);

		printf("%I64d",(ans[0]-L)%L);

		for(i=1;i<n;i++)

          printf(" %I64d",(ans[i]-L)%L);

		printf("\n");

	}

	return 0;

}


 

 

你可能感兴趣的:(HDU)