【取模除法+较大组合数】 0524_1002.Grids Astar第二战_Failed

Grids

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
  
  
  度度熊最近很喜欢玩游戏。这一天他在纸上画了一个2行N列的长方形格子。他想把1到2N这些数依次放进去,但是为了使格子看起来优美,他想找到使每行每列都递增的方案。不过画了很久,他发现方案数实在是太多了。度度熊想知道,有多少种放数字的方法能满足上面的条件?
 

Input
  
  
  第一行为数据组数T(1<=T<=100000)。   然后T行,每行为一个数N(1<=N<=1000000)表示长方形的大小。
 

Output
  
  
  对于每组数据,输出符合题意的方案数。由于数字可能非常大,你只需要把最后的结果对1000000007取模即可。
 

Sample Input
  
  
2 1 3
 

Sample Output
  
  
Case #1: 1 Case #2: 5
Hint
对于第二组样例,共5种方案,具体方案为:

Wrong Answer Code:(大数取模 除法方面神烦)

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

long long lim=1000000007;
//   (a / b) % m = ( a % (m*b)) / b 
//    ( (a%m) * (b^(-1)%m ) % m   both_prime
long long answer(long long N)
{
	long long b_n1=41666667;
	//int mod24=0;
	long long ans1=N%lim;
	long long ans2=(ans1*N)%lim;
	long long ans3=(ans2*N)%lim;
	long long ans4=(ans3*N)%lim;
	long long ret=( ( (9*ans4)%lim -(74*ans3)%lim 
					+(243*ans2)%lim-(322*ans1)%lim+168 )*(b_n1) ) %lim   ;
	return ret;
}

int main()
{
	int T=0;
	long long N=0;
	scanf("%d",&T);
	for(int i=1;i<=T;i++) 
	{
		scanf("%lld",&N);
		printf("Case #%d:\n%lld\n",i,answer(N));
	}
	
	return 0;
} 

【取模除法】:From _小秋 xuhanqiu


通用公式:                 (a / b) % m = ( a % (m*b)) / b

笔者注:鉴于ACM题目特别喜欢M=1000000007,为质数:

当gcd(b,m) = 1, 有性质: (a/b)%m = (a*b^-1)%m, 其中b^-1是b模m的逆元.

求出b相对于m的逆元b^(-1),即b*(b^(-1)) = 1 (mod m)。有b*b^(-1) - km = 1,其中k是一整数. 用Extended Euclid算法可以求出`b^(-1)。然后计算a*b^(-1) mod m = ( (a%m) * (b^(-1)%m ) % m; 其值与(a/b) mod m相同

推导:a/b = x (mod m) --两边同乘一个数--> a = bx (mod m) ---x=b^-1a-> a = (b^-1) ba (mod m)

再利用b^-1*b = 1(mod m) . 所以可以得出 x = b^-1*a是成立的。

      所以 (a/b) mod m 的解与 (a*b^-1)%m的解是一样的。 而后着可以利用模对乘法的线性性



 Idea From _YCZ:C(2n,n)/(n+1)


Now I am AC:

#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const long long M=1000000007;

ll Jval[2000001];
void Jc_init() //初始化阶乘值的数组
{
	Jval[0]=1;
	for(int i=1;i<=2000000;i++)
	Jval[i]=(i*Jval[i-1])%M;
}

/*************TOOSLOW!!!*********************
ll _Ni(ll x)
{
	ll _ni;
	int cnt=0;
	while(1)
	{
		_ni=cnt*M+1;
		cnt++;
		if(_ni%x == 0)
		{
	//		cout<<"_ni/x \t" <<_ni/x <<endl;
			return _ni/x;
		}
	}
}
********************************************/

//三元组gcd(a,b) == ax +by == d;   
 struct gcdstruct{     //定义结构体存储(For _Ni的计算)
        ll d;  
        ll x;  
        ll y;  
};  
gcdstruct EXTENDED_EUCLID(ll a,ll b)  //EUCLID算法
{  
    gcdstruct aa,bb;  
    if(b==0){  
             aa.d = a;  
             aa.x = 1;  
             aa.y = 0;  
             return aa;  
            }  
    else{  
         bb = EXTENDED_EUCLID(b,a%b);   
         aa.d = bb.d;  
         aa.x = bb.y;  
         aa.y = bb.x - bb.y * (a/b);  
         }  
    return aa;  
}   
    
ll _Ni(ll a,ll m)  //获得a对m的模逆元
 {  
      ll x;  
      gcdstruct aa;  
      aa = EXTENDED_EUCLID(a,m);  
      return aa.x;  
}     


ll C(ll N)//Jval[2N]/Jval[N]/Jval[N] //获得C(2n,n)的组合数结果
{ 
	ll Cans=	(	Jval[2*N]*_Ni(Jval[N],M)   ) %M;
		Cans=	 (	Cans *_Ni(Jval[N],M)   ) %M;
//		cout<<"Jval[2N]:"<<Jval[2*N]<<endl;
//		cout<<"Jval[N]:"<<Jval[N]<<endl;
//	cout<<"Cans: \t"<<Cans<<endl; 
	return Cans; 
}


ll solve(ll N)
{
	ll answer=C(N)%M *_Ni(N+1,M) ;
	return (answer%M+M) % M;
}

int main()
{
	int T=0;
	ll N=0;
	Jc_init();
	scanf("%d",&T);
	for(int cnt=1;cnt<=T;cnt++) 
	{
		scanf("%lld",&N);
		printf("Case #%d:\n%lld\n",cnt,solve(N));
	}
	
	return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糖果天王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值