题意: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[t]为f[i]%k==t的i的个数,
求g[0]∧g[1]∧g[2]∧...∧g[k−1]
思路:
f[1]=1,f[2]=3,f[3]=4,f[4]=9,f[5]=10;
可以发现f[i]的三进制表示正好是i的二进制表示
比如f[4]=9,9的三进制是100,4的二进制也是100
因此,可以推出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 <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <map>
#include <vector>
#define PI acos(-1.0);
#define inf 0x3ffffff
using namespace std;
typedef long long LL;
typedef unsigned int UI;
LL dp[70][70000]; //长i位且模k余j的数有多少个
LL p[70]; //p[i]表示3^i
int dig[70]; //二进制数的每一位
LL g[70000]; //所求的g函数
LL tmp[70][70000]; //用于求dp
int temp;
LL n,k;
LL ans;
void dfs(int len, int r, bool limit) //当前位数,之前得到的余数,是否有限制
{
if(len < 0)
{
g[r]++;
return ;
}
if(!limit && dp[len][0] != -1) //记忆化
{
for(int i = 0; i < k; i++)
{
int x=(r * p[len+1] % k + i) % k;
g[x] += dp[len][i];
}
return ;
}
int cur = temp;
if(!limit) //如果没有限制,为了求dp的值,先将g数组赋值给tmp数组
{
temp++;
for(int i=0;i<k;i++)
{
tmp[cur][i] = g[i];
}
}
int max_digit = limit ? dig[len] : 1;
for(int now = 0; now <= max_digit; now++) //枚举当前位,再dfs
{
dfs(len - 1, (r * 3 + now) % k, limit && now == max_digit);
}
if(!limit) //如果没有限制,则求出dp值为dfs前后g数组增加的值
{
for(int i=0;i<k;i++)
{
dp[len][i]=g[i]-tmp[cur][i];
}
}
return ;
}
void sovle(LL n)
{
int len = 0; //位数
while (n > 0)
{
dig[len++] = n % 2; //将n转化为二进制,并将每一位存入dig数组
n /= 2;
}
temp = 0;
dfs(len - 1, 0, true);
}
int main()
{
int case_cnt;
scanf("%d",&case_cnt);
for (int case_id = 1; case_id <= case_cnt; ++case_id)
{
scanf("%lld%lld",&n,&k);
memset(dp, -1, sizeof(dp));
memset(g, 0, sizeof(g));
p[0] = 1;
for(int i = 1; i < 70; i++)
{
p[i] = p[i-1] * 3 % k; //预处理3的i次方
}
ans=0;
sovle(n);
//因为我们得到的是0~n的结果,题目要求1~n的结果,所以应去掉0%k的结果
g[0]--;
for(int i=0;i<k;i++)
{
ans^=g[i];
}
printf("%lld\n",ans);
}
return 0;
}