HDU 5666 Segment 数论+大数
题目链接:
hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5666
bc(中文):http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=688&pid=1002
题解:
首先可以统计出三角形内所有的点数,(q-2)+(q-3)+...+1=(q-1)*(q-2)/2
其次只要减去被线段割到的点,对于线段xi+yi=q,割到的点有gcd(xi,yi)-1=gcd(xi,q-xi)-1=gcd(xi,q)-1;由于q为质数,所以没有没被割到的点。
综上所述,答案为(q-1)*(q-2)/2;
由于(q-1)*(q-2)超过long long 的范围,所以不能直接求解。
以下提供两种解题方案。
1、用java求大数:
1 import java.util.*; 2 import java.math.*; 3 public class Main { 4 public static void main(String args[]){ 5 Scanner cin = new Scanner(System.in); 6 long q,P; 7 int tc=cin.nextInt(); 8 9 while((tc--)>0){ 10 q=cin.nextLong(); 11 P=cin.nextLong(); 12 BigInteger q1=new BigInteger(Long.toString(q-1)); 13 BigInteger q2=new BigInteger(Long.toString(q-2)); 14 BigInteger ans=q1.multiply(q2); 15 ans=ans.divide(BigInteger.valueOf(2)); 16 ans=ans.remainder(new BigInteger(Long.toString(P))); 17 System.out.println(ans.toString()); 18 } 19 } 20 }
2、模拟笔算二进制乘法
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 7 const int maxn=1e5+10; 8 typedef long long LL; 9 10 const LL ONE=1; 11 LL mul(LL a,LL b,LL p){ 12 LL ret=0; 13 for(;b>0;b>>=1){ 14 if(b&1){ 15 ret+=a; 16 ret%=p; 17 } 18 a=(a+a)%p; 19 } 20 return ret; 21 } 22 23 int main() { 24 int tc; 25 scanf("%d",&tc); 26 while(tc--) { 27 LL q,p; 28 scanf("%lld%lld",&q,&p); 29 LL q1=q-1,q2=q-2; 30 if(q1&1) q2/=2; 31 else q1/=2; 32 LL ans=mul(q1,q2,p); 33 printf("%lld\n",ans); 34 } 35 return 0; 36 }