HDU 3923 Invoker 普通染色:乘法逆元与扩展欧几里得

c种颜色给n个珠子染色:

1.旋转:

将环顺时针旋转i格后,循环节个数为gcd(n,i), 染色方案为  ∑c^gcd(n,i)    其中 i=1~n ;


gcd代码:

LL gcd(LL a,LL b)  
{  
    return b==0?a:gcd(b,a%b);  
}  


2.翻转 :

这里也得考虑两种情况。

        当n为奇数时,共有n个循环节个数(n/2+1)循环群,还有的资料上说是环的个数为(n/2+1) ,注意这是计算机上的表示,n/2整型相除计算机得到的是整数,其实应该写成(n+1)/2。染色方案为  n*c^(n/2+1)

       拿正三角形为例,给它三个顶点染色, 对称轴是一个顶点与其对边终点连线所在的直线,这样的直线有3(n=3,即n个顶点) 条,共有3(n)个循环群。假设第一个顶点在对称轴上,那么第二个顶点经过对称轴翻转肯定和第三个顶点重合,那么 (2,3)是一个循环节,(1)自己是一个循环节,循环节个数为2,即(n+1/2) ;

        当n为偶数时,共有n个循环群,其中有n/2个的循环节个数为(n/2 +1), 有n/2个的循环节个数为(n/2)。

拿正方形为例,四个顶点从左上角顺时针编号1,2,3,4.  

当以1,3顶点连线所在直线为对称轴时(对角的两个顶点):这样对称轴有2个(n/2),经过翻转,2,4 重合,1和1重合,3和3重合,那么循环节的个数为3(2,4) (1)(3), 即(n/2+1)。 染色方案为  (n/2)*c^(n/2+1)

当以两条相对平行的边的中点连线所在直线为对称轴时 :  比如以线段1,2的中点和3,4的中点连线的所在直线为对称轴,这样的对称轴有两个(n/2),经过翻转,1,2重合,3,4重合,循环节的个数为2,(1,2)(3,4),即(n/2)。也就是谁和谁重合,谁就和谁在一个循环节里染色方案为(n/2)*c^(n/2)


快速幂代码:

LL power(LL p,LL n)//快速幂运算  
{  
    LL ans=1;  
    while(n)  
    {  
        if(n&1)  
            ans=ans*p%mod;  
        p=p*p%mod;  
        n/=2;  
    }  
    return ans;  
} 


最后:累加得ans除以置换群个数 2*nans/(2*n)%mod即为最后答案

注意:ans是在计算过程中不断取模得到的数,ans 2*n都在模剩余系中,不能直接参与除法计算,因为有公式a*b%mod=  (a%mod*b%mod)%mod,除法对取余不满足结合律,a/b!=((a%mod)/(b%mod))%mod ,在计算ans/(2*n)%mod时,可以转化为ans*inv(2*n)%mod ,其中  inv(2*n)2*n 关于mod的逆元,保证乘以inv(2*n)和除以2*n 对于最后的答案取余mod是一样。


方法1:扩展欧几里得:  a*x=1(mod P),  gcd(a,p)=1, 其中x为a的逆元


模P乘法逆元
对于整数a、p,如果存在整数b,满足ab mod p =1,则说,b是a的模p乘法逆元。
定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1


一般情况下,ax+by=1;得 x为a mod  b 的逆元,y为 b mod a的逆元

//函数外使用 gcd(2*n,mod,x,y);
LL  exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法,返回a,b的最大公约数,ax+by=gcd(a,b),x,y为方程的一组解
{                                   
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL d=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

最后算出x可能为负数,需要转换成正数并取模:

x=(x+mod)%mod;


方法2:费马小定理:  如果模P是素数的话,那么inv(a)=pow(a,p-2)%p; 等式右边用快速幂运算可以得出

x=power(2*n,mod-2)%mod;

参考:http://www.xuebuyuan.com/1394391.html


Invoker

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 122768/62768 K (Java/Others)
Total Submission(s): 1818    Accepted Submission(s): 815


Problem Description
On of Vance's favourite hero is Invoker, Kael. As many people knows Kael can control the elements and combine them to invoke a powerful skill. Vance like Kael very much so he changes the map to make Kael more powerful. 

In his new map, Kael can control n kind of elements and he can put m elements equal-spacedly on a magic ring and combine them to invoke a new skill. But if a arrangement can change into another by rotate the magic ring or reverse the ring along the axis, they will invoke the same skill. Now give you n and m how many different skill can Kael invoke? As the number maybe too large, just output the answer mod 1000000007.
 

Input
The first line contains a single positive integer T( T <= 500 ), indicates the number of test cases.
For each test case: give you two positive integers n and m. ( 1 <= n, m <= 10000 )
 

Output
For each test case: output the case number as shown and then output the answer mod 1000000007 in a line. Look sample for more information.
 

Sample Input
  
2 3 4 1 2
 

Sample Output
  
Case #1: 21 Case #2: 1
Hint
For Case #1: we assume a,b,c are the 3 kinds of elements. Here are the 21 different arrangements to invoke the skills / aaaa / aaab / aaac / aabb / aabc / aacc / abab / / abac / abbb / abbc / abcb / abcc / acac / acbc / / accc / bbbb / bbbc / bbcc / bcbc / bccc / cccc /
 

Source
 

Recommend
xubiao
 

Statistic |  Submit |  Discuss |  Note


传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3923


AC code:

#include<cstdio>
using namespace std;

typedef long long LL;
const LL mod=1000000007;
LL c,n;

LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}

LL power(LL p,LL n)//快速幂运算
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=ans*p%mod;
        p=p*p%mod;
        n/=2;
    }
    return ans;
}
//函数外使用 gcd(2*n,mod,x,y);
LL  exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法,返回a,b的最大公约数,ax+by=gcd(a,b),x,y为方程的一组解
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL d=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

int main()
{
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        scanf("%d%d",&c,&n);
        int ans=0;
        for(LL i=1;i<=n;i++)
        {
            ans+=power(c,gcd(n,i));
            ans%=mod;
        }

        if(n%2==1)
            ans+=(n*power(c,n/2+1))%mod;
        else
            ans+=((n/2*power(c,n/2+1))%mod+(n/2*power(c,n/2))%mod)%mod;
        ans%=mod;
        LL x,y;
        exgcd(2*n,mod,x,y);
        x=(x+mod)%mod;
        printf("Case #%d: %lld\n",cas++,ans*x%mod);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值