bzoj 2326: [HNOI2011]数学作业

题目描述
小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题:
给定正整数 N 和 M,要求计算 Concatenate (1 .. N) Mod M 的值,其中 Concatenate (1 ..N)是将所有正整数 1, 2, …, N 顺序连接起来得到的数。例如,N = 13, Concatenate (1 .. N)=12345678910111213.小C 想了大半天终于意识到这是一道不可能手算出来的题目,于是他只好向你求助,希望你能编写一个程序帮他解决这个问题。

解题报告:
这题还是比较简单的,很容易想到递推式:\(f[i]=f[i-1]*w+i\),其中\(w\)为i的pow(10,i的位数)
然后我们就分w为不同值讨论,然后分别用矩阵快速幂求一下即可
矩阵大概是:

\[ \begin{matrix} f[i] & i & 1 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \end{matrix} \tag{1} \]

\[ \begin{matrix} w & 0 & 0 \\ 1 & 1 & 0 \\ 0 & 1 & 1 \end{matrix} \tag{2} \]

这里顺便吐槽一下pow这个东西,实在是太辣鸡了,在很多oj上仿佛都有问题,如果死WA的同学,可以手写了,也许就过了

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=4;
int mod;ll n,f[15];
struct mat{
	ll a[N][N];
	mat(){memset(a,0,sizeof(a));}
	mat operator *(const mat r)const{
		mat tmp;
		for(int i=1;i<N;i++)
			for(int j=1;j<N;j++){
				for(int k=1;k<N;k++)
					tmp.a[i][j]+=(a[i][k]*r.a[k][j])%mod,tmp.a[i][j]%=mod;
			}
		return tmp;
	}
};
ll qm(ll x,ll k){
	ll sum=1;
	while(k){
		if(k&1)sum*=x;
		x*=x;k>>=1;
	}
	return sum;
}
void work()
{
	cin>>n>>mod;
	for(int i=1;i<=9;i++)
		f[i]=f[i-1]*10+i,f[i]%=mod;
	int m=0;ll tmp=n;
	while(tmp){
		m++;tmp/=10;
	}
	if(n<=9){
		printf("%lld\n",f[n]%mod);
		return ;
	}
	ll s,t,k,last=f[9];
	for(int i=1;i<m-1;i++){
		s=qm(10,i);
		t=(qm(10,i+1)-1);
		k=t-s+1;
		mat S,T;
		S.a[1][1]=last;
		S.a[1][2]=s;S.a[1][2]%=mod;
		S.a[1][3]=1;
		T.a[1][1]=t+1;T.a[1][1]%=mod;
		T.a[2][1]=1;T.a[2][2]=1;T.a[3][2]=1;T.a[3][3]=1;
		while(k){
			if(k&1)S=S*T;
			T=T*T;k>>=1;
		}
		last=S.a[1][1];
	}
	mat S,T;
	t=qm(10,m-1);s=qm(10,m);
	S.a[1][1]=last;
	S.a[1][2]=t;S.a[1][2]%=mod;
	S.a[1][3]=1;
 	T.a[1][1]=s;T.a[1][1]%=mod;
	T.a[2][1]=1;T.a[2][2]=1;T.a[3][2]=1;T.a[3][3]=1;
	k=n-t+1;
	while(k){
		if(k&1)S=S*T;
		T=T*T;k>>=1;
	}
	printf("%lld\n",S.a[1][1]%mod);
}

int main()
{
	freopen("mathwork.in","r",stdin);
	freopen("mathwork.out","w",stdout);
	work();
	return 0;
}

posted @ 2017-09-12 08:52  PIPIBoss  阅读(101)  评论(0编辑  收藏  举报