http://media.hihocoder.com/contests/icpcbeijing2015/problems.pdf
题意:
给你两个数n(n<=1e18),mod(mod=3,5,7,257,65537)
定义f(x):
f(1)=1;
已知:3*f(n)*f(2*n+1)=f(2*n)*(1+3*f(n));
f(2*n)<6*f(n);
将f(1)~f(n)%mod。
结果:求模之后结果为0~mod-1的数字的数量的异或。
分析:
这个题只要找出来规律就是一个简单的数位dp,规律就是n写成二进制的方法,用三进制来计算例如5=101,结果f[5]=101(三进制)=10;
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=62;
ll dp[maxn][5][65538];
int mp[65538],a[maxn],mm;
int mo;
ll n;
int yu[maxn];
ll dfs(int pos,int v,bool limit)
{
if(pos==-1) return (v==0);
if(!limit&&dp[pos][mm][v]!=-1) return dp[pos][mm][v];
ll ans=0;
int end=limit?a[pos]:1;
int vv=v;
for(int i=0;i<=end;i++)
{
if(i&1) {v-=yu[pos];v=(v+mo)%mo;}
ans+=dfs(pos-1,v,limit&&i==end);
}
if(!limit) dp[pos][mm][vv]=ans;
return ans;
}
ll solve(ll x)
{
// cout<<x<<endl;
mm=mp[mo];
yu[0]=1;
for(int i=1;i<maxn;i++)yu[i]=(yu[i-1]*3)%mo;
int pos=0;
while(x)
{
a[pos++]=x&1;
x>>=1;
}
ll ans=0;
for(int i=0;i<mo;i++)
{
ans^=(dfs(pos-1,i,1)-(i==0));
//cout<<(dfs(pos-1,i,1)-(i==0))<<endl;
}
return ans;
}
int main()
{
mp[3]=0;mp[5]=1;mp[17]=2;
mp[257]=3;mp[65537]=4;
memset(dp,-1,sizeof(dp));
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%lld%d",&n,&mo);
printf("%lld\n",solve(n));
}
return 0;
}