UPC 5215: Fence Building

 


                                                    5215: Fence Building

                                                                   时间限制: 1 Sec  内存限制: 128 MB
                                                                              提交: 377  解决: 68
                                                                   [提交] [状态] [讨论版] [命题人:admin]

题目描述

                                                                   

Farmer John owns a farm. He first builds a circle fence. Then, he will choose n points and build some straight fences connecting them. Next, he will feed a cow in each region so that cows cannot play with each other without breaking the fences. In order to feed more cows, he also wants to have as many regions as possible. However, he is busy building fences now, so he needs your help to determine what is the maximum number of cows he can feed if he chooses these n points properly.

 

输入

The first line contains an integer 1 ≤ T ≤ 100000, the number of test cases. For each test case, there is one line that contains an integer n. It is guaranteed that 1 ≤ T ≤ 105 and 1 ≤ n ≤ 1018 .

 

输出

For each test case, you should output a line ”Case #i: ans” where i is the test case number, starting from 1 and ans is the remainder of the maximum number of cows farmer John can feed when divided by 109 + 7.
 

 

样例输入

3
1
3
5
​
 

样例输出

Case #1: 1
Case #2: 4
Case #3: 16

题目大意 n个点两两相连,看能将圆最多分成多少块

用到了  欧拉示性公式 F=E-V+2; 欧拉示性公式讲解视频

F为所有E条线分成的块的数量(包括图形外那一个块); E为边的数量(带上圆上的曲边);V为顶点的数量;

         V (点的数量)                       注意:(是组合数的写法形式,意思就是从n里边选4个有几种情况)

         E(边的数量)                    

带入

 

最后的试子

显然此题不包括外边的那一个块,所以 F=E-V+1;

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const   ll m=1e9+7 ;

ll qpow(ll a,ll b,ll p)
{
    ll tmp = 1;
    while(b)
    {
        if(1&b) tmp = (tmp*a)%p;
        a = (a*a)%p;
        b>>=1;
    }
    return tmp;
}
ll inv(ll a,ll p) //费马小定理求逆元
{
    return qpow(a,p-2,p);
}

int main ()
{
   int T;
   ll  n;
   ll a,b;

   a=inv(2,m);
   b=inv(24,m);


   scanf("%d",&T);
   int i=0;
   while (T--)
{
    scanf("%lld",&n);
    ll n1,n2,n3,n4;

    n1=n%m;
    n2=(n-1)%m;
    n3=(n-2)%m;
    n4=(n-3)%m;

    i++;
    ll ans=( n1*n2%m*a%m+n1*n2%m*n3%m*n4%m*b%m+1)%m;
    //cout <<"Case #"<<i<<": "<<(ans+m)%m<<endl;  超时    
    printf ("Case #%d: %lld\n",i,ans);                  //换成scanf 和printf 的输入输出方式,加快输入输出速度,避免超时

}

return 0;

}

另外,我还整理了一个Lucas算法的写法(卢卡斯算法)此算法主要解决 n 比 mod 大的情况

主要利用了  费马小定理 和 组合数 的算法模板

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long ll;

//ll mod;
const ll mod=1e9+7;

ll q_pow(ll x,ll n)
{
    ll ans=1;

    while(n>0)
    {
        if(n&1) ans=ans*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return ans;
}

ll inv(ll x)
{
    return q_pow(x,mod-2);

}

ll C(ll n,ll m)
{
    ll sum=1;
    if(n<m)
        return 0;
    else
    {
        for(int i=1;i<=m;i++)
        {
           sum=sum*((n-m+i)%mod*inv(i)%mod)%mod;
        }
        return sum;
    }

}

ll Lucas(ll n,ll m)
{
    if(n<mod&&m<mod)
        return C(n,m);
    else
    {
        return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
    }
}
int main()
{

     ll t,n;
     int cas=1;
     //  calJc();
     scanf("%lld",&t);
     while(t--){
         scanf("%lld",&n);
         printf("Case #%d: %lld\n",cas++,(C(n,2)+C(n,4)+1)%mod);
     }
     return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41199502/article/details/81914584
UPC