您的位置:首页 > 其它

Hihocoder 1259 :A Math Problem(2015 北京区域赛 K,二进制的数位dp)

2016-08-12 19:59 726 查看
提交传送门:Hihocoder 1259 :A Math Problem

题意传送门:UVA Live 7271 A Math Problem

题意:f[1]=1,3∗f[n]∗(f[2∗n]+1)=f[2∗n]∗(1+3∗f[n]),f[2∗n]<6∗f[n],

定义g[t]为f[i]%k==t的i的个数,

求g[0]∧g[1]∧g[2]∧...∧g[k−1]

思路:可以推出f[2∗n]=f[n]∗3,f[2∗n+1]=f[n]∗3+1,

而f[n]=sta[x]∗3x+sta[x−1]∗3(x−1)+...+sta[0]∗30,sta[0]表示每一位可以为0或者1

然后利用数位dp就好了

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long num[66537],dp[65][66537],P[65],n,tmp[65][66537];
int dig[100],sz;
bool vis[100];
int k;

void dfs(int pos,int remain,int limit){
if(pos<0){
num[remain]++;
return ;
}
if(!limit&&vis[pos]){
int rr=remain*P[pos+1]%k;
for(int i=0;i<k;i++)
num[ (rr+i)%k ]+=dp[pos][i];
return ;
}
int now=sz;
if(!limit)
++sz,memcpy(tmp[now],num,k*sizeof(long long));
int last=(limit==0 ? 1:dig[pos]);
for(int i=0;i<=last;i++)
dfs(pos-1,(remain*3+i)%k,limit && (i==last) );
if(!limit){
vis[pos]=true;
for(int i=0;i<k;i++)
dp[pos][i]=num[i]-tmp[now][i];
}
}

void solve(long long m){
int ed=0;
for(int i=0;i<=63;i++){
if((1LL<<i)&m)
ed=i,dig[i]=1;
else
dig[i]=0;
}
dfs(ed,0,1);
}

int main(){
int _;
scanf("%d",&_);
while(_--){
scanf("%lld%d",&n,&k);
memset(vis,false,sizeof(vis));
memset(num,0,sizeof(num));
memset(dp,0,k*sizeof(long long));
memset(tmp,0,k*sizeof(long long));
P[0]=1,sz=0;
for(int i=1;i<=64;i++)
P[i]=P[i-1]*3%k;
solve(n);
long long ans=0;
num[0]--;
for(int i=0;i<k;i++)
ans^=num[i];
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: