2015ACM/ICPC 北京站 K题 数论 + 搜索

来源:互联网 发布:数据融合技术类型 编辑:程序博客网 时间:2024/06/05 06:25

题目链接


题意:
给定一个数列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;}