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