思路:先根据公式中,3f(n)和1+3f(n)互质的关系,列出等式,可以推出,f(n)是一个3进制数。
所以dp的时候按三进制展开就行。
因为模数不定,所以每次都要把模数传进去,其次对于f%k==t,考虑将其转化成(f-t)%k==0,这样就可以放dp里面记忆化。
dp[mod][re][pos]表示第pos为余数为re,模数为mod.
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=7e4+7;
typedef long long ll;
ll n;
int mod;
int flag;
ll p[100];
int a[100];
ll dp[6][70][maxn];
void init(int pos)
{
p[0]=1;
p[1]=3;
for(int i=2;i<=pos;i++)
{
p[i]=p[i-1]*3%mod;
}
}
int solve(ll n)
{
int pos=0;
while(n)
{
a[pos++]=n&1;
n>>=1;
}
return pos;
}
ll dfs(int pos,int v,bool limit)
{
if(pos==-1) return v==0;
if(limit==0&&dp[flag][pos][v]!=-1) return dp[flag][pos][v];
int up=limit?a[pos]:1;
ll ans=0;
for(int i=0;i<=up;i++)
{
ans+=dfs(pos-1,(v-i*p[pos]+mod)%mod,limit&&i==a[pos]);
}
if(limit==0) dp[flag][pos][v]=ans;
return ans;
}
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
memset(dp,-1,sizeof(dp));
while(T--)
{
scanf("%lld%d",&n,&mod);
if(mod==3) flag=0;
else if(mod==5) flag=1;
else if(mod==17) flag=2;
else if(mod==257) flag=3;
else flag=4;
int pos=solve(n);
init(pos);
ll ans=0;
for(int i=0;i<mod;i++)
{
ans^=dfs(pos-1,i,1)-(i==0);
}
printf("%lld\n",ans);
}
return 0;
}