随笔-14  评论-21  文章-0  trackbacks-0

我在网上看到了一个算法,把它实现并且直接AC了

但是,我仔细思考了一会以后,自己cha掉了自己的AC程序,以下是cha掉我程序的数据:(应该也能cha掉很多人吧)

1
51 0
0 2 3

正确结果应该为0

很多算法都默认了pi^ci是有原根的,然而不一定,当pi=2且ci>2时,它没有原根!!(强烈怀疑没有这种数据)



算法还是从头讲吧,我的算法比较暴力,但是肯定是对的

可以通过中国剩余定理直接求出N

计算ANS的值时,可以分别计算出它模pi^ci的值,然后再用中国剩余定理(第二次用……)把它们合并起来

接下来的问题是,记mi=pi^ci,计算1^A+2^A+...+N^A (mod mi),由于N很大,然而N mod mi=bi<=100

于是只要能求出1^A+2^A+...+mi^A的值Si,则Ans=[N/mi]*Si+1^A+2^A+...+bi^A (mod mi),其中1^A+2^A+...+bi^A可以通过求快速幂算出

由于A>=50,故A>ci,所以pi^A|mi,Si=1^A+...+(pi-1)^A+(pi+1)^A+...+(2pi-1)^A+(2pi+1)^A+...

{1,...,pi-1,pi+1,...,2pi-1,2pi+1,...}这些数正好是不超过mi且与之互质的phi(mi)=(pi-1)*pi^(ci-1)个数,即模mi的即约剩余系,记为集合P




如果mi有原根,即当pi!=2或ci<=2时:由于原根有phi(phi(mi))个,我们不妨暴力的从1开始枚举并判断

判断x是否为原根时,可以从小到大枚举phi(mi)的约数作为指数,通过快速幂求出x^phi(mi),得到x的指标

得到原根g后,有P={1,g,g^2,...,g^(phi(mi)-1)},此时Si=1^A+g^A+g^2A+...+g^(phi(mi)-1)A,这是一个等比数列可以用矩阵乘法进行计算



如果mi没有原根,即pi=2且ci>=3时:有这么一个定理:存在g使得P={1,g,g^2,...,g^(k-1),-1,-g,-g^2,...,-g^(k-1)},其中k=2^(ci-2)

可以用类似求原根的方法得到g,则当A为奇数时Si=0,否则Si=2(1^A+g^A+g^2A+...+g^(k-1)A),这还是一个等比数列……



于是问题得到解决,代码如下:


#include <iostream>
#include 
<cstdlib>

using namespace std;

struct matrix {int a,b,c; }e,f,re;

void multi(matrix u,matrix v,matrix &res,const int &mo)
{
  res.a
=(long long)(u.a)*v.a%mo;
  res.c
=(long long)(u.c)*v.c%mo;
  res.b
=((long long)(u.b)*v.a+(long long)(u.c)*v.b)%mo;
}

int seq(int g,int n,int mo)
{
  re
=e; f.a=g;
  f.b
=f.c=1;
  n
--;
  
while(n>0)
  {
    
if (n&1)
      multi(re,f,re,mo);
    multi(f,f,f,mo);
    n
>>=1;
  }
  
return (re.a+re.b)%mo;
}

long long _pow(long long a,long long d)

  
long long res=1;
  
while (d>0)
  { 
    
if (d&1) res=a*res;
    a
=a*a;
    d
>>=1;
  }
  
return res;
}

long long pow(long long a,long long d,long long n)

  
long long res=1;
  
while (d>0)
  { 
    
if (d&1) res=a*res%n;
    a
=a*a%n;
    d
>>=1;
  }
  
return res;
}

int ord(int a,int n,int f)
{
  
int i;
  
for (i=1;i*i<=f;i++)
  {
    
if (f%i!=0continue;
    
if (pow(a,i,n)==1)
      
return i;
  }
  
for(i--;i>=1;i--)
  {
    
if (f%i!=0continue;
    
if (pow(a,f/i,n)==1)
      
return f/i;
  }
}

int findg(int n,int f)
{
  
for(int i=1;i<=n;i++)
    
if (ord(i,n,f)==f)
      
return i;
}

void exgcd(long long a,long long b,long long &d,long long &x,long long &y)
{
  
if (!b) { d=a; x=1; y=0; }
  
else {
    exgcd(b,a
%b,d,y,x);
    y
-=x*(a/b);
  }
}

bool china(long long &a1,long long &m1,long long a2,long long m2)
{
  
long long d,x,y,aa,mm,t;
  exgcd(m1,m2,d,x,y);
  
if ((a2-a1)%d) return false;
  x
=(x%m2+m2)%m2;
  t
=((a2-a1)%m2+m2)%m2;
  x
=(a2-a1)/d*x;
  x
=(x%m2+m2)%m2;
  mm
=m1/d*m2;
  aa
=((x*m1+a1)%mm+mm)%mm;
  a1
=aa; m1=mm;
  
return true;
}

int A,n,b[25],p[25],c[25];
long long N,M,pc[25],res,resM,t;

int main(void)
{
  
int u,i,j,k,cases,g;
  scanf(
"%d",&u);
  cases
=u;
  e.a
=e.c=1; e.b=0;
  
while(u--)
  {
    scanf(
"%d%d",&A,&n);
    N
=0; M=1;
    
for(i=0;i<=n;i++)
    {
      scanf(
"%d%d%d",b+i,p+i,c+i);
      pc[i]
=_pow(p[i],c[i]);
      china(N,M,b[i],pc[i]);
    }
    
if (N==0) N=M;
    res
=0; resM=1;
    
for(i=0;i<=n;i++)
    {
      
if ((p[i]&1)||(c[i]<=2))
      {
        k
=pc[i]-pc[i]/p[i];
        g
=findg(pc[i],k);
        t
=seq(pow(g,A,pc[i]),k,pc[i]);
      }
      
else
      {
        
if (A&1) t=0;
        
else
        {
          k
=(pc[i]>>2);
          g
=findg(pc[i],k);
          t
=(seq(pow(g,A,pc[i]),k,pc[i])<<1)%pc[i];
        }
      }
      t
=t*(N/pc[i])%pc[i];
      
for(j=1;j<=b[i];j++)
        t
=(t+pow(j,A,pc[i]))%pc[i];
      china(res,resM,t,pc[i]);
    }
    printf(
"Case %d: %d\n",cases-u,int(res));
  }
  
return 0;
}




posted on 2010-10-12 16:57 zxb 阅读(430) 评论(8)  编辑 收藏 引用

评论:
# re: fzu1971 A math problem 2010-10-22 14:02 | jieyj
phi(mi)应该等于(pi-1)*pi^(ci-1)吧?  回复  更多评论
  
# re: fzu1971 A math problem 2010-10-23 20:10 | zxb
@jieyj
嗯,打错了,已修改  回复  更多评论
  
# re: fzu1971 A math problem 2010-11-11 22:50 | zmh
请问:Ans=[N/mi]*Si+1^A+2^A+...+bi^A (mod mi),是怎么来的,没看懂.  回复  更多评论
  
# re: fzu1971 A math problem 2010-11-11 22:55 | zxb
@zmh
在算要求的式子模mi的值,而此时有N%mi=bi  回复  更多评论
  
# re: fzu1971 A math problem 2010-11-11 23:04 | zmh
我还是不明白,N^A只其中的一项.   回复  更多评论
  
# re: fzu1971 A math problem 2010-11-12 14:50 | zxb
@zmh
Si=1^A+2^A+...+mi^A=(mi+1)^A+(mi+2)^A+...+(mi+mi)^A=.......
每mi项的结果是相同的  回复  更多评论
  
# re: fzu1971 A math problem 2011-02-05 17:36 | AekdyCoin
数据里面有这种数据的……
话说这题2^k可以讨论……  回复  更多评论
  
# re: fzu1971 A math problem 2011-02-05 20:42 | zxb
@AekdyCoin
数据里面有没有我不知道,反正我一开始的程序会被我给的那组数据cha掉但是在fzu上AC了

2^k的情况我没有细想……反正我的方法是比较暴力的~  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理