bzoj 3329: Xorequ【数位dp+矩阵乘法】

注意第一问不取模!!!
因为a+b=a|b+a&b,ab=a|b-a&b,所以a+b=ab+2(a&b)
x3x==2x可根据异或的性质以转成x2x==3x,根据上面的推导,得到
x^2x=x+2x-2
(x&2x)3x;
3x-2*(x&2x)
3x;
x&2x0;
x&(x<<1)
0
也就是说x在二进制下不能有相邻的1
第一问用数位dp瞎搞一下就行
第二问,考虑递推,设f[i]为n==i的答案,已知f[n-1],f[n],求f[n+1],考虑在新增的位置上放0,那么剩下n个位置可以随便放,也就是f[n];在新增的位置上放1,那么n-1位一定要放0,剩下n-1个位置可以随便放,也就是f[n-1],所以f[n+1]=f[n]+f[n-1],就是斐波那契数列,用矩阵乘法加速即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
long long T,n,b[65],tot,x,ha[65][2];
struct qwe
{
	long long a[5][5];
	void clr()
	{
		a[1][1]=a[1][2]=a[2][1]=a[2][2]=0;
	}
	qwe operator * (const qwe &b) const
	{
		qwe c;
		for(int i=1;i<=2;i++)
			for(int j=1;j<=2;j++)
			{
				c.a[i][j]=0;
				for(int k=1;k<=2;k++)
					c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%mod;
			}
		return c;
	}
}aa;
long long dfs(int w,int lm,int la)
{
	if(!w)
		return 1;
	if(!lm&&ha[w][la])
		return ha[w][la];
	if(lm)
	{
		if(b[w]==0||la==1)
			return dfs(w-1,b[w]==0,0);
		else
			return dfs(w-1,0,0)+dfs(w-1,1,1);
	}
	if(la==1)
		ha[w][la]=dfs(w-1,0,0);
	else
		ha[w][la]=dfs(w-1,0,0)+dfs(w-1,0,1);
	return ha[w][la];
}
int main()
{
	scanf("%lld",&T);
	aa.a[1][2]=aa.a[2][1]=aa.a[2][2]=1;
	while(T--)
	{
		memset(b,0,sizeof(b));
		memset(ha,0,sizeof(ha));
		scanf("%lld",&n);
		tot=0;x=n;
		while(x)
			b[++tot]=x%2,x/=2;
		qwe r,a=aa;
		r.a[1][1]=r.a[2][2]=1,r.a[1][2]=r.a[2][1]=0;
		x=n+1;
		while(x)
		{
			if(x&1)
				r=r*a;
			a=a*a;
			x>>=1;
		}
		printf("%lld\n%lld\n",dfs(tot,1,0)-1,(r.a[1][1]+r.a[1][2])%mod);
	}
	return 0;
}
posted @ 2018-09-06 09:33  lokiii  阅读(133)  评论(0编辑  收藏  举报