BZOJ3329 Xorequ[数位DP+递推矩阵快速幂]

数    位    D    P    开    long    long

首先第一问是转化。

于是就可以二进制下DP了。

第二问是递推,假设最后$n-1$个01位的填法设为$f[i-1]$(方案包括0),于是有fib数列递推关系(很好推),然后矩阵快速幂即可。

一开始思路有点乱,导致边界初始化屡次出错。

WA1:见标题赤字。

WA2:初始化写错了。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 typedef pair<int,int> pii;
11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 ll f[65][2];//mistake:long long
21 int T,b[65];
22 ll n;//mistake:long long
23 ll dp(int len,int las,int limit){
24     if(!len)return 1;
25     if(!limit&&~f[len][las])return f[len][las];
26     int num=limit?b[len]:1;ll ret=0;
27     for(register int i=0;i<=num;++i)
28         ret+=las?(i?0:dp(len-1,0,limit&&i==num)):dp(len-1,i,limit&&i==num);
29     return limit?ret:f[len][las]=ret;
30 }
31 inline ll task1(ll x){
32     int len=0;while(x)b[++len]=x&1,x>>=1;
33     return dp(len,0,1)-1;
34 }
35 const int P=1e9+7;
36 struct matrix{
37     int a[2][2];
38     matrix(){a[0][0]=a[1][1]=1,a[0][1]=a[1][0]=0;}
39     inline void build(){a[0][0]=0,a[0][1]=a[1][0]=a[1][1]=1;}
40     inline matrix operator *(const matrix&A)const{
41         matrix B;
42         B.a[0][0]=(a[0][0]*1ll*A.a[0][0]+a[0][1]*1ll*A.a[1][0])%P;
43         B.a[0][1]=(a[0][0]*1ll*A.a[0][1]+a[0][1]*1ll*A.a[1][1])%P;
44         B.a[1][0]=(a[1][0]*1ll*A.a[0][0]+a[1][1]*1ll*A.a[1][0])%P;
45         B.a[1][1]=(a[1][0]*1ll*A.a[0][1]+a[1][1]*1ll*A.a[1][1])%P;
46         return B;
47     }
48     inline void operator *=(const matrix&A){*this=*this * A;}
49 };
50 inline int task2(ll p){
51     if(p==1)return 2;
52     if(p==2)return 3;
53     matrix ret,x;x.build();p-=2;
54     for(;p;p>>=1,x*=x)if(p&1)ret*=x;
55     return (ret.a[1][1]*1ll*3+ret.a[0][1]*1ll*2)%P;
56 }
57 
58 int main(){//freopen("test.in","r",stdin);freopen("test.ans","w",stdout);
59     memset(f,-1,sizeof f);
60     read(T);while(T--)read(n),printf("%lld\n%d\n",task1(n),task2(n));
61     return 0;
62 }
View Code

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11528765.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值