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 }

 

posted @ 2016-04-17 22:55  fenicnn  阅读(323)  评论(0编辑  收藏  举报