【BZOJ3329】Xorequ 數位DP+矩陣乘法
阿新 • • 發佈:2017-08-20
cnblogs -- -1 ron 後來 sam [] led 矩陣
1
2
【BZOJ3329】Xorequ
Description
Input
第一行一個正整數,表示數據組數據 ,接下來T行
每行一個正整數N
Output
2*T行
第2*i-1行表示第i個數據中問題一的解,
第2*i行表示第i個數據中問題二的解,
Sample Input
11
Sample Output
12
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; }
【BZOJ3329】Xorequ 數位DP+矩陣乘法