常州Day4题解
1. 高精度
这题略水,字符串可过,还不加压位等,操作只有BitShift和add/sub,不过编程复杂度有些高.(输出都是二进制我能说些什么...)
2. N皇后问题 (警告! 不是平时你见到的N皇后问题...是一道Hash的模拟题,N皇后的位置都给你了,就是统计)
二级标题很详细了,搜索那些解N皇后问题的千万莫戳进来.
3. Sam数
一道比较有意思的题.
题意是,给定一个k,求所有k位数中所有相邻两位数差都小于等于2的数.输出$\mod{10^9+7}$
说的不够明白.来个例子:
$2134678$ 这是一个符合要求的7阶Sam数.
$6987688$ 这个不符合,$\left| 9-6\right|=3>2$
很明显,当$k=1$时输出$10$.
当$k=2$时,很明显最高位不可为0.
于是第一位只能为$1~9$.
第二位呢?显然不可能是$0~10$.限制条件摆那儿呢!
于是想到,第二位是$0$的时候有两种可能,即$10$和$20$.这是从第一位是$0,1,2$的地方推导来的.
于是递推式很明显,$F[i,j]=\sum_{n=j-2}^{j+2}F[i-1,n]\text{While n}\in\text{0~9}$
可是数据范围:
$30\% k\le 10^6,60\% k\le 10^{12},100\% 10^{18}$
吓,$10^6 \cdot 10$都基本爆空间好么? 逗我呢?
注意到每次递推只需用到前一次的结果,用滚动数组即可. 30分到手.
但是,十的十八次位数这是要闹那样!!!
车到山前必有路(话说我当时还没想到).
注意这是线性递推.每次递推后的$F[i]$都是前一次值的线性组合($\text{linear combination}$),而这事可以用矩阵乘法解决.矩阵乘法遵守结合率,可以使用二分快速幂在$O(\log{n})$时间内求出.至于矩阵乘法的复杂度...他不会随着输入数据的上升而上升,$O(n^3)$中n恒等于10,即是常数时间,只是常数比较大.
时间复杂度是$O(1000 \cdot \log(n))=O(\log{n})$.
矩阵方法详细参数:
变换矩阵:
$tr=\left[ \begin{array} {lcr}
1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 \\
0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1
\end{array} \right]$
初始向量:
$i=\left[ \begin{array} {lcr}
0 \\
1 \\
1 \\
1 \\
1 \\
1 \\
1 \\
1 \\
1 \\
1
\end{array} \right]$
递推结果为$c = tr^k \cdot i$
结果
$$sum=\sum_{i \in c}c[i]$$
注意随时求余.特判k=1.
最后一题代码(前两题还要?自己写去..)
#include "cstdio" #define modulo 1000000007 #include "cstring" struct mat{ long long m[10][10],i,j,k,t; void cpy(mat b){ for(i=0;i<10;++i) for(j=0;j<10;++j) m[i][j]=b.m[i][j]; } void mul(mat a){ mat tempa; for(i=0;i<10;++i){ for(j=0;j<10;++j){ t=0; for(k=0;k<10;++k){ t+=m[k][i]*a.m[j][k]; } tempa.m[i][j]=t % modulo; } } cpy(tempa); } void toUnit(){ memset(m,0,sizeof(m)); for(i=0;i<10;++i){ m[i][i]=1;//unit in matrix computation,oops... } } } matt,tt; struct vect{ long long m[10],tm; int i,j; void mul(mat a){ for(i=0;i<10;++i){ tm=0; for(j=0;j<10;++j){ tm+=m[i]*a.m[i][j]; } m[i]=tm % modulo; } } } vec; long long n,ac; void fastPow(long long n){ if(n&1){ tt.cpy(matt); }else{ tt.toUnit(); } while(n>>=1){ matt.mul(matt); if(n&1){ tt.mul(matt); } } } const long long pa[10]={0,1,1,1,1,1,1,1,1,1}; const long long pb[10][10]={ {1,1,1,0,0,0,0,0,0,0}, {1,1,1,1,0,0,0,0,0,0}, {1,1,1,1,1,0,0,0,0,0}, {0,1,1,1,1,1,0,0,0,0}, {0,0,1,1,1,1,1,0,0,0}, {0,0,0,1,1,1,1,1,0,0}, {0,0,0,0,1,1,1,1,1,0}, {0,0,0,0,0,1,1,1,1,1}, {0,0,0,0,0,0,1,1,1,1}, {0,0,0,0,0,0,0,1,1,1} }; int main(){ scanf("%lld",&n); if(n==1){ printf("10\n"); return 0; } memcpy(vec.m,pa,sizeof(pa)); memcpy(matt.m,pb,sizeof(pb)); fastPow(n-1);//幂次修正 vec.mul(tt); ac=0; for(int i=0;i<10;++i){ ac+=vec.m[i]; } printf("%lld\n",ac % modulo); return 0; }