HDU 4291解题报告
来源:互联网 发布:域名买卖网 编辑:程序博客网 时间:2024/05/17 20:22
A Short problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1838 Accepted Submission(s): 670
Hence they prefer problems short, too. Here is a short one:
Given n (1 <= n <= 1018), You should solve for
where
Please process until EOF (End Of File).
012
0142837
这道题是比较裸的矩阵快速幂的题。但是与一般的题不一样的就是取模的是复合函数,而且是对最外层的取模,因此内部的数字可能会非常大。g(n)=3*g(n-1)+g(n-2)这个是标准的二阶线性递推式,我们可以类比斐波那契数列的公式。令Y=g(g(x)),mod=1000000007,则所求的转换成了g(Y)%mod的结果。这里出现了取模的符号。而本题的特点就在于数字会非常大。我们也知道二阶线性递推式取模必然会出现周期性的循环。因此我们可以暴力模拟得出g(Y)%mod的Y的周期,得到Y的周期为t1=222222224,即g(g(g(x)))%mod=g(g(g(x))-k*t1)%mod,所以计算时为了缩小范围我们只需计算g(g(x))%t1的值即可。即g(g(g(x)))%mod=g(g(g(x))%t1)%mod。要计算g(g(x))%t1,这样我们再次令Z=g(x),则此时所求结果为g(Z)%t1,这是可以得到Z的周期为t2=183120,即g(g(x))%t1=g(g(x)%t2)%t1。这样所求为g(x)%t2,我们再次暴力模拟,得到x的周期为t3=240。所以最终所求结果为g(g(g(x)))%mod=g(g(g(x%t3)%t2)%t1)%mod。这样通过层层取模我们便可以减小所得的数字的规模,防止数字过大导致的溢出问题。
通过这道题的训练,我们发现该题的难点不在矩阵快速幂。因为我们很清楚的知道,当出现线性递推式时,而且在n特别大时就应该有矩阵快速幂降低复杂度的意识。而本题的复合函数是一个难点。而突破这个难点就要从取模周期上降低数字的规模。取模的周期性这些小的技巧在这种难题中我们一定要注意。往往容易被忽视的小技巧才是解决问题的关键之处。
参考代码:
#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#include<string>#include<vector>#include<map>#include<set>#include<stack>#include<queue>#include<ctime>#include<cstdlib>#include<iomanip>#include<utility>#define pb push_back#define mp make_pair#define CLR(x) memset(x,0,sizeof(x))#define _CLR(x) memset(x,-1,sizeof(x))#define REP(i,n) for(int i=0;i<n;i++)#define Debug(x) cout<<#x<<"="<<x<<" "<<endl#define REP(i,l,r) for(int i=l;i<=r;i++)#define rep(i,l,r) for(int i=l;i<r;i++)#define RREP(i,l,r) for(int i=l;i>=r;i--)#define rrep(i,l,r) for(int i=1;i>r;i--)#define read(x) scanf("%d",&x)#define put(x) printf("%d\n",x)#define ll long long#define lson l,m,rt<<1#define rson m+1,r,rt<<11using namespace std;int T1=222222224,T2=183120,T3=240,mod=1000000007;ll n;struct mat{ ll d[2][2];}A,B,E;mat multi(mat a,mat b,int mod){ mat ans; rep(i,0,2) { rep(j,0,2) { ans.d[i][j]=0; rep(k,0,2) { if(a.d[i][k]&&b.d[k][j]) ans.d[i][j]=(ans.d[i][j]+a.d[i][k]*b.d[k][j])%mod; } } } return ans;}mat quickmulti(mat a,ll n,int mod){ mat ans=E; while(n) { if(n&1) { n--; ans=multi(ans,a,mod); } else { n>>=1; a=multi(a,a,mod); } } return ans;}int main(){ A.d[0][0]=3,A.d[0][1]=1,A.d[1][0]=1,A.d[1][1]=0; B.d[0][0]=1,B.d[0][1]=0,B.d[1][0]=0,B.d[1][1]=0; E.d[0][0]=1,E.d[0][1]=0,E.d[1][0]=0,E.d[1][1]=1; while(~scanf("%I64d",&n)) { n%=T3; mat ans=quickmulti(A,n,T2); ans=multi(ans,B,T2); int shu=ans.d[1][0]; ans=quickmulti(A,shu,T1); ans=multi(ans,B,T1); shu=ans.d[1][0]; ans=quickmulti(A,shu,mod); ans=multi(ans,B,mod); printf("%I64d\n",ans.d[1][0]); }}
- HDU 4291解题报告
- HDU 3342 解题报告
- HDU 3336 解题报告
- HDU 3335 解题报告
- hdu 2516解题报告
- hdu 1004解题报告
- hdu 2139解题报告
- hdu 1019解题报告
- hdu 1064 解题报告
- HDU 1113 解题报告
- hdu 1068 解题报告
- HDU:2050解题报告
- hdu 4001解题报告
- hdu 1005解题报告
- HDU解题报告--1003
- HDU解题报告--1004
- HDU解题报告--1005
- HDU 1005 解题报告
- Maven原理和Maven2新特性
- mac 上python简易爬虫
- 你的能量超乎想象-记2014.9-2015.2
- libxl库的使用
- 干支纪年,2015为什么是乙未年?
- HDU 4291解题报告
- Android API之android.provider.ContactsContract.Contacts
- Lucene学习总结之一:全文检索的基本原理
- Android API之android.provider.ContactsContract
- C/C++ 中typedef 用法总结
- 使用手机调试Android app不能连接的问题
- Windows编程中的各种文件操作方法及其头文件
- Hiberante组件关联映射
- 求n个随机数里第二大值的两种方法