【NOIP2005普及组T4】循环-高精度

测试地址:循环

做法:两年了!!两年来,我数次挑战,屡败屡战,屡战屡败,终于在今天,终于把这题AC了!

好吧回归主题。我们设L(k)为尾k位的循环节长度,不难发现L(k)=mL(k-1),其中1≤m≤10,不难发现m为n^L(k-1),n^(2L(k-1)),...中第k位的循环节长度。因此,我们只需从小到大枚举位数now,然后在n^L(now-1),n^(2L(now-1)),...中找第now位的循环节长度,因为循环节长度≤10,所以如果枚举超过10次仍然没有出现循环,则表明无解,否则,最后的结果就是各位的m的乘积。

(其实明白了也并不怎么难嘛...)

以下是本人代码:

#include 
#include 
#include 
#include 
#include 
struct hp {int s[210];} n,a,b,ans;
char N[110];
int k,now,tmp;

void mult1(hp a,hp b,hp &c,int d)
{
  hp s;
  memset(s.s,0,sizeof(s.s));
  for(int i=1;i<=d;i++)
    for(int j=1;j<=d;j++)
	  s.s[i+j-1]+=a.s[i]*b.s[j];
  for(int i=1;i<=d+1;i++)
    if (s.s[i]>=10)
	{
	  s.s[i+1]+=s.s[i]/10;
	  s.s[i]%=10;
	}
  c=s;
}

void mult2(hp a,int b,hp &c)
{
  hp s;
  memset(s.s,0,sizeof(s.s));
  for(int i=1;i<=200;i++)
    s.s[i]+=a.s[i]*b;
  for(int i=1;i<=200;i++)
    if (s.s[i]>=10)
	{
	  s.s[i+1]+=s.s[i]/10;
	  s.s[i]%=10;
	}
  c=s;
}

int main()
{
  scanf("%s%d",N,&k);
  for(int i=strlen(N)-1,j=1;i>=0;i--,j++)
    n.s[j]=N[i]-'0';
  
  ans.s[1]=1;
  a=n;
  
  for(now=1;now<=k;now++)
  {
	b=n;
	tmp=b.s[now];
	int len=0;
	do
	{
	  mult1(a,b,b,k);
	  len++;
	}while(len<10&&b.s[now]!=tmp);
	if (b.s[now]!=tmp) {printf("-1");return 0;}
	b=a;
	for(int i=1;i<=len-1;i++) mult1(a,b,a,k);
	mult2(ans,len,ans);
  }
  
  int out;
  for(out=200;ans.s[out]==0;out--);
  for(;out>=1;out--)
    printf("%d",ans.s[out]);
  
  return 0;
}


你可能感兴趣的:(算法-高精度)