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^3x==2x → x^3x^x==2x^x → 3x^x^x==2x^x
→ 3x^0==2x^x → 3x==2x^x → x^2x==3x而我们都知道x+2x==3x,而^是二进制上不进位的加法,x^2x的效果与x+2x相同,说明xx和任意一位上都不可能同时是1。然后2x2x是xx左移一位,所以意味着不存在相邻的两位,满足这两位上都是1。于是我们就可以用数位DP来求取xx的方案数。
表示第i位,上面为j(0或1),并且是否被约束。最后的答案就是f[cnt][0][0]+f[cnt][0][1]+f[cnt][1][0]+f[cnt][1][1]-1(cnt表示x二进制下的位数,-1是因为要舍去0这种情况)
对于第二问我们要推一推结论,我们手算几个,设f(x)f(x)表示2x2x时的答案,则f(0)=1,f(1)=2,f(2)=3,f(3)=5,f(5)=8……f(0)=1,f(1)=2,f(2)=3,f(3)=5,f(5)=8……发现f(x)f(x)刚好满足斐波那契数列(只不过开头只有1个1),所以对于f(n)f(n)我们直接用矩阵乘法加速即可。
#include<bits/stdc++.h>
#define MD 1000000007
#define ll long long
using namespace std;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
void print(ll x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
ll T,n,cnt,ans,num[61],f[61][2][2],A[2][2],B[2][2],U[2][2];
void mul(ll a[][2],ll b[][2]){
for(ll i=0;i<2;i++)
for(ll j=0;j<2;j++){
ll res=0;
for(ll k=0;k<2;k++) res=(res+a[i][k]*b[k][j])%MD;
U[i][j]=res;
}
for(ll i=0;i<2;i++)
for(ll j=0;j<2;j++)
a[i][j]=U[i][j];
}
int main()
{
T=read();
while(T--){
memset(f,0,sizeof(f));
n=read();ll p=n;cnt=0;ans=0;
while(p){
cnt++;
if(p&1) num[cnt]=1;
else num[cnt]=0;
p/=2;
}
f[0][0][0]=1;
for(ll i=0;i<cnt;i++)
for(ll k=0;k<2;k++){
if(f[i][0][k]){
f[i+1][0][k|(0<num[cnt-i])]+=f[i][0][k];
if(k||num[cnt-i]==1)f[i+1][1][k]+=f[i][0][k];
}
if(f[i][1][k]){
f[i+1][0][k|(0<num[cnt-i])]+=f[i][1][k];
}
}
ans=(f[cnt][0][0]+f[cnt][0][1]+f[cnt][1][0]+f[cnt][1][1]);
print(ans-1);puts("");
A[0][0]=2;A[0][1]=1;A[1][0]=A[1][1]=0;B[0][0]=B[0][1]=B[1][0]=1;B[1][1]=0;
if(n==0){puts("1");continue;}
p=(n-1);
while(p){
if(p&1) mul(A,B);
mul(B,B);p/=2;
}
print(A[0][0]);puts("");
}
return 0;
}
本文探讨了使用数位动态规划(数位DP)和矩阵乘法解决特定形式方程的有效方法。通过分析方程x^3x=2x的特性,我们发现了解决此类问题的关键在于理解二进制位运算和斐波那契数列之间的联系。文章详细解释了如何利用这些数学概念来高效求解,并提供了具体的算法实现。
1817

被折叠的 条评论
为什么被折叠?



