[Jzoj] 1351. 阅读程序写结果

题目描述

NOIP2009普及组初赛阅读程序第三题如下:
  const c = 2009;
  var
   n, p, s, i, j, t: integer;
  begin
   read(n, p);
   s := 0;
   t := 1;
   for i := 1 to n do
   begin
   t := t * p mod c;
   for j := 1 to i do
   s := (s + t) mod c;
   end;
   writeln(s);
  end.
  输入:11 2
  输出:______
  这题很简单,死做都能做出来,但如果扩大N的范围,你还能做吗?

题目解析

首先题目求的是: F [ N ] = ∑ i = 1 N i × p i m o d 2009 F[N]=\sum_{i=1}^{N}i\times p^imod 2009 F[N]=i=1Ni×pimod2009

因此可以求出递推式: F [ N ] = F [ N − 1 ] + N × p N F[N]=F[N-1]+N\times p^N F[N]=F[N1]+N×pN

考虑一下矩阵快速幂加速,推出矩阵:
[Jzoj] 1351. 阅读程序写结果_第1张图片

因为 N N N很大,所以要用到高精度

代码

#include
using namespace std;
#define ll long long
const ll M=2009;
ll f[5],a[5][5],p;
void mul(ll f[]) 
{
    ll c[5];memset(c,0,sizeof(c));
    for(ll i=1;i<=3;i++)for(ll j=1;j<=3;j++)c[i]=(c[i]+a[j][i]*f[j]%M)%M;
    memcpy(f,c,sizeof(c));
}
void times() 
{
    ll c[5][5];memset(c,0,sizeof(c));
    for(ll i=1;i<=3;i++)for(ll j=1;j<=3;j++)for(ll k=1;k<=3;k++)c[i][j]=(c[i][j]+a[k][j]*a[i][k]%M)%M;
    memcpy(a,c,sizeof(c));
}
struct A 
{
    ll num[1005];
    void read() 
	{
      char s[1005];
      scanf("%s",s);
      if(s[0]=='0') 
	  {
        num[0]=0;
        return;
      }
      num[0]=strlen(s);
      for(ll i=num[0];i;i--) num[i]=s[num[0]-i]-'0';
    }
    void div() 
	{
      for(ll i=num[0];i;i--)
       if(i!=1) 
	   {
	   	 if(num[i]%2==1) num[i-1]+=10;
         num[i]/=2;
       } 
	   else num[i]/=2;
      while(!num[num[0]]&&num[0])num[0]--;
    }
}n;
void fun(A n,ll p) 
{
    f[1]=f[2]=p;
    a[1][1]=a[1][2]=a[2][2]=p;
    a[2][3]=a[3][3]=1;
    while(n.num[0])
	{
      if(n.num[1]&1) mul(f);
      times();
      n.div();
    }
    printf("%d",f[3]);
}
int main() 
{
    n.read();
    cin>>p;
    fun(n,p);
    return 0;
}

你可能感兴趣的:([Jzoj] 1351. 阅读程序写结果)