题意:已知f(1)=1,还有f(n)的一堆关系,定义g(t)为f(i)%k==t 的个数。求g(0)^g(1)....^g(k-1)。
思路;先化简公式可以得到,f(2n)=3f(n),f(2n+1)=3f(n)+1,很明显就要把一个数化成二进制,然后每一位的权值=3^(位数-1),然后就用数位dp统计就好了。代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<utility>
#include<map>
#define maxn 65540
#define inf 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int mod = 1e9 + 7;
int num[70], k, vis[maxn];
LL temp[maxn], dp[70][maxn], three[70];
void dfs(int pos, int status, int limit){
if (pos < 1){
temp[status]++;
return;
}
if (!limit&&vis[pos]){
int now = status*three[pos + 1] % k;
for (int i = 0; i < k; i++){
temp[(now + i) % k] += dp[pos][i];
}
return;
}
int end = limit ? num[pos] : 1;
for (int i = 0; i <= end; i++)
dfs(pos - 1, (status * 3 + i) % k, limit&&i == end);
if (!limit){
vis[pos] = 1;
for (int i = 0; i < k; i++){
dp[pos][i] = temp[i];
}
}
}
void solve(LL x){
int len = 0;
while (x){
num[++len] = x & 1;
x >>= 1;
}
dfs(len, 0, 1);
}
int main(){
three[1] = 1;
int t;
scanf("%d", &t);
while (t--){
memset(temp, 0, sizeof(temp));
memset(dp, -1, sizeof(dp));
memset(vis, 0, sizeof(vis));
LL n;
scanf("%lld%d", &n, &k);
for (int i = 2; i < 70; i++){
three[i] = three[i - 1] * 3 % k;
}
solve(n);
temp[0]--;
LL ans = 0;
for (int i = 0; i<k; i++){
ans ^= temp[i];
}
printf("%lld\n", ans);
}
}