【BZOJ3329】Xorequ 数位DP+矩阵乘法

【BZOJ3329】Xorequ

Description

Input

第一行一个正整数,表示数据组数据 ,接下来T行
每行一个正整数N

Output

2*T行
第2*i-1行表示第i个数据中问题一的解,

第2*i行表示第i个数据中问题二的解,

Sample Input

1
1

Sample Output

1
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;
}

 

posted @ 2017-08-20 08:54  CQzhangyu  阅读(275)  评论(0编辑  收藏  举报