HNOI2011 数学作业

传送门

这个题……多么希望他是可以(O(n))做的呀……取模练习题

考虑一下用(f[i])表示到第i个数的结果,很容易得到:(f[i] = f[i-1] * 10^k + i)。其中k是当前数的位数。

这个显然可以用矩乘优化……不过因为k是变量,所以麻烦一点……不过不要紧,对于不同位数的数我们分开做就好了。

然后好像我的写法兼容性还不错……不是特别需要考虑什么10的指数幂之类的特例。不过我还是调了好久……因为我忘了矩乘不满足交换律……

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('
')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define fr friend inline
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;

ll read()
{
   ll ans = 0,op = 1;
   char ch = getchar();
   while(ch < '0' || ch > '9')
   {
      if(ch == '-') op = -1;
      ch = getchar();
   }
   while(ch >='0' && ch <= '9')
   {
      ans *= 10;
      ans += ch - '0';
      ch = getchar();
   }
   return ans * op;
}

ll n,m,cur = 1;

struct matrix
{
   ll f[4][4];
   matrix(){memset(f,0,sizeof(f));}
   fr matrix operator * (const matrix &a,const matrix &b)
   {
      matrix c;
      rep(i,0,2)
     rep(j,0,2)
     rep(k,0,2)
     c.f[i][j] += a.f[i][k] * b.f[k][j],c.f[i][j] %= m;
      return c;
   }
   fr matrix operator ^ (matrix a,ll b)
   {
      matrix c;
      rep(i,0,2) c.f[i][i] = 1;
      while(b)
      {
     if(b & 1) c = c * a;
     a = a * a,b >>= 1;
      }
      return c;
   }
}F,D,E;

int main()
{
   F.f[0][1] = 1,F.f[1][1] = 1,F.f[1][2] = 1,F.f[2][2] = 1;
   D.f[1][0] = D.f[2][0] = 1;
   n = read(),m = read();
   while(n >= pow(10,cur))
   {
      F.f[0][0] = (ll)pow(10,cur) % m;
      D = (F ^ (ll)(pow(10,cur) - (ll)pow(10,cur-1))) * D;
      cur++;
   }
   n -= (ll)pow(10,cur-1);
   F.f[0][0] = (ll)pow(10,cur) % m;
   F = F ^ (n+1),D = F * D;
   printf("%lld
",D.f[0][0]);
   return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/10147046.html