51nod1436 方程的解数
1436 方程的解数
基准时间限制:1 秒 空间限制:131072 KB
请计算这个方程组有多少合法的整数解,答案比较大,对m取余后输出。
对于样例,有三组解{1, 1}, {3, 1}, {1, 3}。
Input
单组测试数据。 第一行包含四个整数 n, k, l, m (2 ≤ n ≤ 10^18, 0 ≤ k ≤ 10^18, 0 ≤ l ≤ 64, 1 ≤ m ≤ 10^9 + 7)。
Output
对于每一组数据输出答案占一行。
Input示例
2 1 2 10
Output示例
3
%讨论区里的大佬。
此题由于方程中仅含位操作,所以首先可以考虑将k以二进制的形式分开来看每一位。
假设当前考虑的是k的第i位,那么这一位将由且仅由n个ai的第i位决定,其中,n个数的总情况数为2^n。
若k的第i位为0,那么a1, a2...an中,在第i位上必然不存在相邻的1,设所有满足不存在相邻1的情况数为x;
那么满足使k的第i位为1的情况数就是2^n - x,我们设y = 2^n - x。
于是若k在二进制的0 ~ L位中,存在p个1和q个0,ans即为 y^p * x^q。
对于解x的值,当n = 1,x = 2;当n = 2,x = 3;当n更大的时候,可以考虑第n位的两种情况,若第n位为0那么前n-1位只要满足“不存在相邻1”即可;若第n位为1,那么第n-1位必须为0,而前n-2位满足“不存在相邻1”即可。
于是得到转移方程:dp[n] = dp[n - 1] + dp[n - 2],但是n比较大,无法O(n)递推,但是很庆幸这个转移方程就是Fibonacci数列,很容易想到使用矩阵快速幂进行加速求得某项的值,于是此题得解。
以上内容写的比较啰嗦...
但是友情提示一句,需要特判考虑无解的情况:)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=' ',ch=getchar(); 33 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 35 if(last=='-')ans=-ans; return ans; 36 } 37 ll m; 38 ll nu,n1,n0,np2; 39 struct jz{ 40 ll x[2][2]; 41 jz(){ 42 memset(x,0,sizeof(x)); 43 } 44 friend jz operator *(jz a,jz b){ 45 jz ans; 46 for (int i=0;i<2;i++) 47 for (int j=0;j<2;j++) 48 for (int k=0;k<2;k++) 49 ans.x[i][j]=mo(ans.x[i][j]+a.x[i][k]*b.x[k][j],m); 50 return ans; 51 } 52 friend jz operator ^(jz a,ll b){ 53 jz ans; ans.x[0][0]=1; ans.x[1][1]=1; 54 for (;b;b>>=1,a=a*a) if (b&1) ans=ans*a; 55 return ans; 56 } 57 }A; 58 void Init(ll k,ll n){ 59 60 while (k){ 61 int n_2=k%2LL; k/=2LL; ++nu; 62 if (n_2==0) n0++; 63 else n1++; 64 } 65 np2=powmod(2,n,m); 66 } 67 ll fib(ll n){ 68 A.x[0][0]=0; A.x[0][1]=1; A.x[1][1]=1; A.x[1][0]=1; 69 A=A^n; 70 return mo(A.x[0][0]+A.x[1][0]+A.x[1][0],m); 71 } 72 int main() 73 { 74 ll n=read(),k=read(),l=read(); m=read(); 75 Init(k,n); 76 if (nu>l) { 77 puts("0"); 78 return 0; 79 } 80 n0+=(l-nu); 81 ll x0=fib(n),x1=mo(np2-x0,m); 82 printf("%lld",mo(powmod(x0,n0,m)*powmod(x1,n1,m),m)); 83 return 0; 84 }