P4461 [CQOI2018]九连环

思路:\(DP\)

提交:\(2\)

错因:高精写挂(窝太菜了)

题解:

观察可知\(f[i]=2*f[i-1]+(n\&1)\)
高精的过程参考了WinXP@luogu的思路:

发现一个问题。每一项约等于前一项的 \(2\) 倍。仔细分析,发现
\(dp(n)=2dp(n-1)+ (n\& 1)?1:0\)
既然是 \(2\) 倍,为什么不打一下 \(2\) 进制表示呢?
\(1\ 10 \ 101 \ 1010 \ 10101 \ 101010 \ 1010101......\)
有点意思。
其实也很容易能从\(dp\) 中发现这个规律,每当 \(n\) 为奇数时 \(++\) ,就会使每隔 \(1\)\(+1\)
这也不太好办。 \(n=1e5\) 时,这个 \(2\) 进制数就有 \(1e5\) 位。 \(10\) 进制的高精位数只知道比 \(1e5\) 小却没有办法确定。隔一位一个 \(1\) 也不方便化成 \(10\) 进制啊。不过好像没有什么好办法能直接从 \(2\) 进制的高精转化为 \(10\) 进制的高精。(仅为思考过程)
能不能直接从 \(10\) 进制的高精推过来呢?
如果是二进制表示是 \(1000000....\) ,它就可以轻松地表示为 \(2^n\) 然后用快速幂做了。
那么现在考虑对这个 \(2\) 进制数 \(×3\) 。哦不对,是 \(11\) 。我们来看变成了什么。。
\(11 \ 110 \ 1111 \ 11110 \ 111111 \ 1111110 ......\)
这就可以说是非常显然了吧。( +1 或 +2 变成 10000... )

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define ll unsigned long long
#define RR register ll
#define R register int
using namespace std;
const int B=1e+8,N=6010;
namespace Luitaryi {
int T,n,sz1,sz2;
ll ret[N],a[N];
inline void mul(ll a[N],int& sz1,ll b[N],int sz2) {
  RR tmp[N]; memset(tmp,0,sizeof(tmp)); for(R i=0;i<=sz1;++i) 
    for(R j=0;j<=sz2;++j) tmp[i+j]+=a[i]*b[j];
  sz1+=sz2; for(R i=0;i<=sz1;++i) tmp[i+1]+=tmp[i]/B,tmp[i]%=B;
  while(tmp[sz1+1]) ++sz1,tmp[sz1+1]+=tmp[sz1]/B,tmp[sz1]%=B;
  memcpy(a,tmp,sizeof(tmp));
}
inline void main() { 
  scanf("%d",&T); while(T--) {
    scanf("%d",&n); R p=n+1; memset(a,0,sizeof(a)),memset(ret,0,sizeof(ret));
    ret[0]=1,a[0]=2; sz1=sz2=0; while(p) {
      if(p&1) mul(ret,sz2,a,sz1); p>>=1;
      if(p) mul(a,sz1,a,sz1); 
    } if(n&1) ++ret[0]; ret[0]-=2; if(ret[0]<0) ret[0]+=B,--ret[1];
    RR k=0; for(R i=sz2;i>=0;--i) k=k*B+ret[i],ret[i]=k/3,k%=3;
    while(!ret[sz2]) --sz2; printf("%llu",ret[sz2]); 
    for(R i=sz2-1;i>=0;--i) printf("%08llu",ret[i]); putchar('\n');
  }
}
} signed main() {Luitaryi::main(); return 0;}

2019.08.23
77

转载于:https://www.cnblogs.com/Jackpei/p/11401935.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值