hdu6121 Build a tree 模拟
Posted 天道酬勤007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu6121 Build a tree 模拟相关的知识,希望对你有一定的参考价值。
/** 题目:hdu6121 Build a tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6121 题意:n个点标号为0~n-1;节点i的父节点为floor((i-1)/k); 0是根节点。 求这个树的所有节点为根的子树的节点数的异或和。 思路:模拟 可以发现k = min(k,n-1);即:k>=n-1时候结果一样。 然后画图可以发现是一个满k叉树(叶子不一定满)。 然后发现:如果这是一个叶子也满的k叉树,那么直接就可以计算出结果。 当不是叶子满的时候,可以发现它的某些地方是满的。那么想办法递归处理从上到下。 将那些满的取下来计算。剩下的继续递归。 当k=1的时候递归时间超限。 从1到n取异或和可以发现前i的前缀异或和有规律4为一周期。1,+1,0,原数; */ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <iostream> #include <cmath> #include <vector> #include <map> using namespace std; typedef long long LL; #define ms(x,y) memset(x,y,sizeof x) typedef pair<int, int> P; const LL INF = 1e10; const int mod = 1e9 + 7; const int maxn = 3e5 + 100; map<LL,LL>mp; void get(LL n,LL k,LL &h,LL &r) { LL p = 1; if(n==1){ h = 0, r = 0; return ; } n -= 1; for(int i = 1; 1; i++){ if(n==p*k){ h = i, r = 0; return ; } if(n/k<p){///如果判断n<=k*p,那么可能要考虑取整。 h = i, r = n; return ; } /*if(log10(n)<log10(p)+log10(k)){ h = i, r = n; return ; }*/ p = p*k; n -= p; } } LL cal(LL h,LL k) { if(h==0) return 1; LL p = 1; LL sum = 1; for(int i = 1; i <= h; i++){ p *= k; sum += p; } return sum; } void work(LL num,LL h,LL k) { if(num==0) return ; LL n = cal(h,k); mp[n] += num; n -= 1; while(n){ mp[n/k] += num*k; n /= k; n -= 1; } } LL Pow(LL a,LL b) { LL p = 1; while(b){ if(b&1) p *= a; a = a*a; b >>= 1; } return p; } void solve(LL n,LL k) { if(n==1){ mp[1]++; return ; } LL h, r; get(n,k,h,r); if(r==0){ work(1,h,k); return ; } if(h==1){ mp[n] += 1; mp[1] += n-1; return ; } LL p = Pow(k,h-1); LL num; if(r%p==0) num = r/p; else num = r/p+1; work(num-1,h-1,k); work(k-num,h-2,k); mp[n]++; solve(n-(num-1)*cal(h-1,k)-(k-num)*cal(h-2,k)-1,k); } void test()///k=1时候的规律。 { for(int i = 1; i <= 20; i++){ printf("%d: ",i); int ans = 0; for(int j = 1; j <= i; j++){ ans ^= j; } printf("%d\n",ans); } } int main() { //freopen("YYnoGCD.in","r",stdin); //freopen("YYnoGCD.out","w",stdout); //freopen("in.txt","r",stdin); int T; //test(); LL n, k; cin>>T; while(T--) { scanf("%lld%lld",&n,&k); LL ans = 0; if(k==1){ if(n%4==0) ans = n; if(n%4==1) ans = 1; if(n%4==2) ans = n+1; if(n%4==3) ans = 0; }else{ k = min(k,n-1); mp.clear(); solve(n,k); map<LL,LL>::iterator it; for(it = mp.begin(); it!=mp.end(); it++){ if((it->second)%2){ ans ^= it->first; } } } cout<<ans<<endl; } return 0; }
以上是关于hdu6121 Build a tree 模拟的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6121 Build a tree —— 2017 Multi-University Training 7
hdu 3932 Groundhog Build Home —— 模拟退火