BZOJ3329Xorequ 数位DP+矩阵乘法
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3329Xorequ 数位DP+矩阵乘法相关的知识,希望对你有一定的参考价值。
【BZOJ3329】Xorequ
Description
Input
第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N
Output
2*T行
第2*i-1行表示第i个数据中问题一的解,
第2*i行表示第i个数据中问题二的解,
Sample Input
1
1
1
Sample Output
1
2
2
HINT
x=1与x=2都是原方程的根,注意第一个问题的解
不要mod 10^9+7
1<=N<=10^18
1<=T<=1000
题解:由于x*3中一位最多只会改动3位,所以我一开始想把所有情况都打个表出来,后来发现这个可以严格证明。
x^(3x)=2x -> x^(2x)=3x -> x^(2x)=x+2x -> x^(2x)=x^(2x)+((x&(2x))<<1) -> x&(2x)=0
也就是说x不能有相邻2位都等于1,第一问直接数位DP即可,不过这个DP式好像就是斐波那契数列的递推公式?所以第二问无脑矩乘即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const ll P=1000000007; ll n; ll f[70]; ll ans; int v[70]; struct node { ll a[5][5]; node () {memset(a,0,sizeof(a));} ll * operator [] (int b) {return a[b];} node operator * (node b) { node c; for(int i=0;i<=1;i++) for(int j=0;j<=1;j++) for(int k=0;k<=1;k++) c[i][j]=(c[i][j]+a[i][k]*b[k][j])%P; return c; } }res,tr; void pm(ll y) { while(y) { if(y&1) res=res*tr; tr=tr*tr,y>>=1; } } void work() { scanf("%lld",&n); int i; ans=0; for(i=60;~i;i--) { if((1ll<<i)&n) { ans+=f[i+1]; if((1ll<<(i+1))&n) break; } } if(i<0) ans++; printf("%lld\n",ans-1); tr[0][0]=tr[0][1]=tr[1][0]=1,tr[1][1]=0; res[0][1]=res[0][0]=1,res[1][0]=res[1][1]=0; pm(n); printf("%lld\n",res[0][0]); } void init() { int i; f[1]=f[0]=1; for(i=2;i<=60;i++) f[i]=f[i-1]+f[i-2]; } int main() { int T; scanf("%d",&T); init(); while(T--) work(); return 0; }
以上是关于BZOJ3329Xorequ 数位DP+矩阵乘法的主要内容,如果未能解决你的问题,请参考以下文章