Hdu 5666 Segment【欧拉函数+技巧乘法】

33 篇文章 0 订阅

Segment

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 999 Accepted Submission(s): 360


Problem Description
Silen August does not like to talk with others.She like to find some interesting problems.

Today she finds an interesting problem.She finds a segment x+y=q .The segment intersect the axis and produce a delta.She links some line between (0,0) and the node on the segment whose coordinate are integers.

Please calculate how many nodes are in the delta and not on the segments,output answer mod P.

Input
First line has a number,T,means testcase number.

Then,each line has two integers q,P.

q is a prime number,and 2q1018,1P1018,1T10.

Output
Output 1 number to each testcase,answer mod P.

Sample Input
  
  
1 2 107

Sample Output
  
  
0

Source

题意:

给出   x+y=q 的q 值

确定q 是素数,连接这条线上所有的格点和原点,求在第一象限中,在由坐标轴和这条直线围成的三角形中,但不在这些线上的所有的格点的个数.



如图,求在大三角中,但是不在红线以及坐标轴上的点的个数


题解:


首先是没读懂题意,直接交了前n 项和,wa.....

后来看明白题意了,瞬间感觉是求欧拉函数,然后各种找规律....联系曾今做过的几个欧拉函数的题目

终于发现了规律!!

(n-2)*euler(n)/2   


然后各种wa.....后来才发现数据范围太大,会中间溢出啊!!

想起前几天学到的取余的方法:把乘法用加法和移位来代替,这样就不会溢出啦~

顺利AC!




/*
http://blog.csdn.net/liuke19950717
*/
#include<cstdio>
#include<cstring>
#include<cmath>
typedef unsigned long long ll;
ll euler(ll x)
{
	ll sum=x;
	for(ll i=2;i*i<=x;++i)
	{
		if(x%i==0)
		{
			x/=i;
			sum=sum-sum/i;
			while(x%i==0)
			{
				x/=i;
			}
		}
	}
	if(x>1)
	{
		sum=sum-sum/x;
	}
	return sum;
}
ll mul(ll n,ll m,ll mod)
{
	ll ans=0;
	while(m)
	{
		if(m&1)
		{
			ans=(ans+n)%mod;
		}
		m>>=1;
		n=(n<<1)%mod;
	}
	return ans;
}
int main()
{
	ll t;
	scanf("%lld",&t);
	while(t--)
	{
		ll n,mod;
		scanf("%lld%lld",&n,&mod);
		ll ans=mul(n-2,euler(n)/2,mod);
		printf("%lld\n",ans%mod);
	}
	return 0;
}


后来整理思路,发现自己走了弯路,因为给出的n 必定为素数,而素数对应的欧拉函数值就是他自身减去1,程序就可以省去一个求解欧拉函数的了,这道题也就成了完全考验找规律和技巧性取模的题目了.....


/*
http://blog.csdn.net/liuke19950717
*/
#include<cstdio>
#include<cstring>
#include<cmath>
typedef unsigned long long ll;
ll mul(ll n,ll m,ll mod)
{
	ll ans=0;
	while(m)
	{
		if(m&1)
		{
			ans=(ans+n)%mod;
		}
		m>>=1;
		n=(n<<1)%mod;
	}
	return ans;
}
int main()
{
	ll t;
	scanf("%lld",&t);
	while(t--)
	{
		ll n,mod;
		scanf("%lld%lld",&n,&mod);
		ll ans=mul(n-2,(n-1)/2,mod);
		printf("%lld\n",ans%mod);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值