HNOI 2011 数学作业

题目链接:http://www.zybbs.org/JudgeOnline/problem.php?id=2326

题目知识:动态规划,矩阵乘法

 

分析:一开始看到数据范围就想到只能构造...想了好长时间也没想出来...后来同学一点拨才发现DP+矩阵加速就好了。

 

首先可以非常简单地得到一个递推式,f[i]表示第i个数mod m的值,则f[i]=f[i-1]*(10^d[i])+i,其中d[i]表示i的位数, 从|f[i-1],i-1,1| ==> |f[i],i,1|可以由矩阵

 

|d[i],0,0|

 

|1,   1,0|

 

|1,   1,1|得来,所以根据矩阵结合律,可以用类似于快速幂的方法求解。时间复杂度O(logn)(貌似是吧)。


View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

struct node
{
int n,m,d[4][4];
};
node ans,d;
long long n,wei,num;
int mod;

node Cheng(node a,node b)
{
node c;
long long temp;
c.n=a.n,c.m=b.m;
for (int i=1;i<=a.n;i++)
for (int j=1;j<=b.m;j++)
{
temp=0;
for (int k=1;k<=a.m;k++)
{
temp+=(long long)a.d[i][k]*b.d[k][j];
if (temp>=mod) temp%=mod;
}
c.d[i][j]=temp;
}
return c;
}

int main()
{
scanf("%lld%d",&n,&mod);
ans.n=1,ans.m=3;
ans.d[1][1]=0,ans.d[1][2]=0,ans.d[1][3]=1;
d.n=3,d.m=3;
wei=1;
while (true)
{
wei*=10;
num=min(wei-1,n)-wei/10+1;
memset(d.d,0,sizeof(d.d));
d.d[1][1]=wei%mod;
d.d[2][1]=d.d[2][2]=d.d[3][1]=d.d[3][2]=d.d[3][3]=1;

while (1)
{
if (num&1) ans=Cheng(ans,d);
num>>=1;if (!num) break;
d=Cheng(d,d);
}
if (wei>n) break;
}
printf("%d\n",ans.d[1][1]);
return 0;
}


看来以后应该试着让自己的思路面广一些,不能死磕着一个思路走啊..

最后膜拜一下XYR。

(吐槽:丫的每年的HNOI都有数学都有平衡树啊...而且非splay无解啊...囧视。HB第一年省选伤不起...)

你可能感兴趣的:(数学)