1. 程式人生 > >2015ACM/ICPC 北京站 K題 數論 + 搜尋

2015ACM/ICPC 北京站 K題 數論 + 搜尋

題目連結

題意:
給定一個數列F,滿足:
F[1]=1
3F[n]F[2n+1]=F[2n](1+3F[n])
F[2n]<6F[n]
然後給你一個n,k,定義g[i]F[1]F[n]k取餘後等於i的個數。
然後問g[0]g[k1]的異或和。

思路:
對於F,考慮第二個條件,化簡可得:

F[2n+1]F[2n]=1+3F[n]3F[n]

設:F[2n]=k3F[n]
F[2n+1]=k(1+3F[n])

因為F[2n]<6F[n]
k>=1
所以k=1
即:
F[2n]=3F[n]
F[2n+1]=1+3F[n]

故我們可以推出
n

為奇數,F[n]=3F[n/2]
n為偶數,F[n]=3F[n/2]+1

故可以考慮DFS,每次可以將問題規模減小一半。

程式碼:

#include<cstdio>
#include<cmath>
#include<set>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

const int A = 1e5 + 10;
ll g[A],tg[A],k;
ll n;

ll calc(ll n){
    if
(n == 1) return 1; if(n&1) return (3*calc(n/2)+1)%k; return 3*calc(n/2)%k; } void dfs(ll n){ if(n == 1){ g[1]++; return; } if(n&1){ dfs(n-1); g[calc(n)]++; } else{ dfs(n/2); for(int i=0 ;i<k ;i++) tg[i] = 0; for
(int i=0 ;i<k ;i++){ tg[(i*3)%k] += g[i]; tg[(i*3+1)%k] += g[i]; } for(int i=0 ;i<k ;i++) g[i] = tg[i]; g[1]++; g[calc(n+1)]--; } } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%lld%lld",&n,&k); memset(g,0,sizeof(g)); dfs(n); ll ans = 0; for(int i=0 ;i<k ;i++){ ans ^= g[i]; } printf("%lld\n",ans); } return 0; }