【HDU】5227 Tom and game【快速求gcd值+点分治】
2015-05-13 16:33
232 查看
传送门:【HDU】5227 Tom and game
前言:
在数论大神队友的帮助下知道了怎么预处理……然后我就套了一个点分治就过了……
题目分析:
其实对于一个四元组,我们可以看成一个狮子堆,他能转移到的状态有多少,他就是多少高的石子堆……然后一条路径上所有的石子堆用来做游戏,其实就相当于经典的取石子的Nim和游戏……只要异或和不为0,先手胜,反之后手胜。
对于路径上异或和不为0的路径条数,我们可以用点分治搞搞,这个没有难度,套一个map就做完了……下面重点说一下预处理。
考虑一个四元组(a,b,c,d)(a,b,c,d)。
当t≤a−1t\leq a-1时,我们有:
∑t=1a−1∑i=1t∑j=1tgcd(i,j) \sum_{t=1}^{a-1}\sum_{i=1}^{t}\sum_{j=1}^{t}gcd(i,j)
当t=a,i≤b−1t=a,i\leq b-1时,我们有:
∑i=1b−1∑j=1agcd(i,j)\sum_{i=1}^{b-1}\sum_{j=1}^{a}gcd(i,j)
当t=a,i=b,j≤c−1t=a,i=b,j\leq c-1时,我们有:
∑j=1c−1gcd(b,j) \sum_{j=1}^{c-1}gcd(b,j)
当t=a,i=b,j=c,k≤d−1t=a,i=b,j=c,k\leq d-1,此时个数就是d-1个。
把上面的值全部累加起来就是对于一个四元组,他的sg值(石子个数)。
然后对于子问题∑ni=1∑mj=1gcd(i,j)\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)我们如何快速的求解。下面直接给一段贾志鹏线性筛里的解法:
∑ni=1∑mj=1gcd(i,j)\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)
=∑ni=1∑mj=1∑d|gcd(i,j)φ(d)=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|gcd(i,j)}\varphi(d)
=∑ni=1∑mj=1∑d|i and d|jφ(d)=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|i~and~d|j}\varphi(d)
=∑min(n,m)d=1φ(d)∑1≤i≤n and d|i∑1≤j≤m and d|j1=\sum_{d=1}^{min(n,m)}\varphi(d)\sum_{1\leq i\leq n~and~d|i}\sum_{1\leq j\leq m~and~d|j}1
=∑min(n,m)d=1φ(d)(∑1≤i≤n and d|i1)(∑1≤j≤m and d|j1)=\sum_{d=1}^{min(n,m)}\varphi(d)(\sum_{1\leq i\leq n~and~d|i}1)(\sum_{1\leq j\leq m~and~d|j}1)
=∑min(n,m)d=1φ(d)⌊nd⌋⌊md⌋=\sum_{d=1}^{min(n,m)}\varphi(d)\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor
然后我们发现⌊nd⌋\lfloor\frac{n}{d}\rfloor只有O(n√)O(\sqrt n)个值,而且⌊nd⌋\lfloor\frac{n}{d}\rfloor和⌊md⌋\lfloor\frac{m}{d}\rfloor是独立的,所以⌊nd⌋⋅⌊md⌋\lfloor\frac{n}{d}\rfloor\cdot\lfloor\frac{m}{d}\rfloor只有O(n√)O(\sqrt n)个值。所以我们在O(n√)O(\sqrt n)的时间内就能处理出一个四元组的sg值。
之后只要我们做一次点分治,求出异或值为0的路径条数cntcnt,然后令路径总数为tottot,则ans=(tot−cnt)totans=\frac{(tot-cnt)}{tot}。
my code:my~~code:
前言:
在数论大神队友的帮助下知道了怎么预处理……然后我就套了一个点分治就过了……
题目分析:
其实对于一个四元组,我们可以看成一个狮子堆,他能转移到的状态有多少,他就是多少高的石子堆……然后一条路径上所有的石子堆用来做游戏,其实就相当于经典的取石子的Nim和游戏……只要异或和不为0,先手胜,反之后手胜。
对于路径上异或和不为0的路径条数,我们可以用点分治搞搞,这个没有难度,套一个map就做完了……下面重点说一下预处理。
考虑一个四元组(a,b,c,d)(a,b,c,d)。
当t≤a−1t\leq a-1时,我们有:
∑t=1a−1∑i=1t∑j=1tgcd(i,j) \sum_{t=1}^{a-1}\sum_{i=1}^{t}\sum_{j=1}^{t}gcd(i,j)
当t=a,i≤b−1t=a,i\leq b-1时,我们有:
∑i=1b−1∑j=1agcd(i,j)\sum_{i=1}^{b-1}\sum_{j=1}^{a}gcd(i,j)
当t=a,i=b,j≤c−1t=a,i=b,j\leq c-1时,我们有:
∑j=1c−1gcd(b,j) \sum_{j=1}^{c-1}gcd(b,j)
当t=a,i=b,j=c,k≤d−1t=a,i=b,j=c,k\leq d-1,此时个数就是d-1个。
把上面的值全部累加起来就是对于一个四元组,他的sg值(石子个数)。
然后对于子问题∑ni=1∑mj=1gcd(i,j)\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)我们如何快速的求解。下面直接给一段贾志鹏线性筛里的解法:
∑ni=1∑mj=1gcd(i,j)\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)
=∑ni=1∑mj=1∑d|gcd(i,j)φ(d)=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|gcd(i,j)}\varphi(d)
=∑ni=1∑mj=1∑d|i and d|jφ(d)=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|i~and~d|j}\varphi(d)
=∑min(n,m)d=1φ(d)∑1≤i≤n and d|i∑1≤j≤m and d|j1=\sum_{d=1}^{min(n,m)}\varphi(d)\sum_{1\leq i\leq n~and~d|i}\sum_{1\leq j\leq m~and~d|j}1
=∑min(n,m)d=1φ(d)(∑1≤i≤n and d|i1)(∑1≤j≤m and d|j1)=\sum_{d=1}^{min(n,m)}\varphi(d)(\sum_{1\leq i\leq n~and~d|i}1)(\sum_{1\leq j\leq m~and~d|j}1)
=∑min(n,m)d=1φ(d)⌊nd⌋⌊md⌋=\sum_{d=1}^{min(n,m)}\varphi(d)\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor
然后我们发现⌊nd⌋\lfloor\frac{n}{d}\rfloor只有O(n√)O(\sqrt n)个值,而且⌊nd⌋\lfloor\frac{n}{d}\rfloor和⌊md⌋\lfloor\frac{m}{d}\rfloor是独立的,所以⌊nd⌋⋅⌊md⌋\lfloor\frac{n}{d}\rfloor\cdot\lfloor\frac{m}{d}\rfloor只有O(n√)O(\sqrt n)个值。所以我们在O(n√)O(\sqrt n)的时间内就能处理出一个四元组的sg值。
之后只要我们做一次点分治,求出异或值为0的路径条数cntcnt,然后令路径总数为tottot,则ans=(tot−cnt)totans=\frac{(tot-cnt)}{tot}。
my code:my~~code:
[code]#include <stdio.h> #include <string.h> #include <map> #include <algorithm> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 10005 ; const int MAXE = 20005 ; struct Edge { int v , n ; Edge () {} Edge ( int v , int n ) : v ( v ) , n ( n ) {} } ; Edge E[MAXE] ; int H[MAXN] , cntE ; int phi[MAXN] ; LL val[MAXN] ; LL S[MAXN] , top ; LL ct[MAXN] ; int ans ; int n ; int Q[MAXN] , head , tail ; map < LL , int > mp ; int vis[MAXN] ; int siz[MAXN] ; int pre[MAXN] ; int gcd ( int a , int b ) { return b ? gcd ( b , a % b ) : a ; } void init () { ans = 0 ; cntE = 0 ; clr ( H , -1 ) ; clr ( vis , 0 ) ; } void addedge ( int u , int v ) { E[cntE] = Edge ( v , H[u] ) ; H[u] = cntE ++ ; } LL get ( int n , int m ) { LL res = 0 ; if ( n > m ) swap ( n , m ) ; for ( int i = 1 , j ; i <= n ; i = j + 1 ) { j = min ( n / ( n / i ) , m / ( m / i ) ) ; res += ( LL ) ( phi[j] - phi[i - 1] ) * ( n / i ) * ( m / i ) ; } return res ; } void preprocess () { for ( int i = 0 ; i <= 10000 ; ++ i ) { phi[i] = i ; } for ( int i = 2 ; i <= 10000 ; ++ i ) if ( phi[i] == i ) { for ( int j = i ; j <= 10000 ; j += i ) { phi[j] = phi[j] / i * ( i - 1 ) ; } } for ( int i = 2 ; i <= 10000 ; ++ i ) { phi[i] += phi[i - 1] ; } for ( int t = 1 ; t <= 10000 ; ++ t ) { ct[t] = get ( t , t ) + ct[t - 1] ; } } int get_root ( int s ) { head = tail = 0 ; Q[tail ++] = s ; pre[s] = 0 ; while ( head != tail ) { int u = Q[head ++] ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; pre[v] = u ; Q[tail ++] = v ; } } int root_siz = tail , root = s ; while ( head ) { int u = Q[-- head] , cnt = 1 ; siz[u] = 1 ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == pre[u] ) continue ; siz[u] += siz[v] ; if ( siz[v] > cnt ) cnt = siz[v] ; } cnt = max ( cnt , tail - siz[u] ) ; if ( cnt < root_siz ) { root_siz = cnt ; root = u ; } } return root ; } void get_val ( int u , int f , LL value ) { S[top ++] = value ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] || v == f ) continue ; get_val ( v , u , value ^ val[v] ) ; } } void dfs ( int u ) { int root = get_root ( u ) ; vis[root] = 1 ; mp.clear () ; if ( !val[root] ) ++ ans ; for ( int i = H[root] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] ) continue ; top = 0 ; get_val ( v , root , val[v] ) ; for ( int j = 0 ; j < top ; ++ j ) { map < LL , int > :: iterator it = mp.find ( S[j] ^ val[root] ) ; if ( it != mp.end () ) ans += it->second * 2 ; if ( !( S[j] ^ val[root] ) ) ans += 2 ; } for ( int j = 0 ; j < top ; ++ j ) { mp[S[j]] ++ ; } } for ( int i = H[root] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( vis[v] ) continue ; dfs ( v ) ; } } void solve () { int t , a , b , c ; init () ; for ( int i = 1 ; i < n ; ++ i ) { scanf ( "%d%d" , &a , &b ) ; addedge ( a , b ) ; addedge ( b , a ) ; } for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d%d%d%d" , &t , &a , &b , &c ) ; val[i] = ct[t - 1] + c - 1 ; val[i] += get ( a - 1 , t ) ; val[i] += get ( a , b - 1 ) - get ( a - 1 , b - 1 ) ; } dfs ( 1 ) ; ans = n * n - ans ; int x = gcd ( n * n , ans ) ; printf ( "%d/%d\n" , ans / x , n * n / x ) ; } int main () { preprocess () ; while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
相关文章推荐
- 组合数(Lucas定理) + 快速幂 --- HDU 5226 Tom and matrix
- 组合数(Lucas定理) + 快速幂 --- HDU 5226 Tom and matrix
- HDU 3071 Gcd & Lcm game
- Zoj 3529 A Game Between Alice and Bob 数论+博弈Nim 快速求数中有多少个素数因子
- hdu 5226 Tom and matrix (推公式,lucas)
- HDU_5224 Tom and paper
- hdu 4497 GCD and LCM
- hdu 5945 Fxx and Game dp(单调队列优化)
- [hdu 5945 Fxx and game] dp+单调队列
- hdu 4497 GCD and LCM
- hdu 5495 Fxx and game(dp+单调队列优化)
- hdu 5226 Tom and matrix && BestCoder Round #40
- hdu 4497 GCD and LCM 质因素分解+排列组合or容斥原理
- HDU 1849 Rabbit and Grass(Nim game)
- HDU 5863 cjj's string game(矩阵快速幂)
- HDU 4742 Pinball Game 3D(CDQ分治)
- HDU 1848 Fibonacci again and again && HDU 1851 A Simple Game (基础sg函数)
- hdu 5945 Fxx and game(dp+单调队列)
- hdu(4497) GCD and LCM
- 杭电hdu 1849 Rabbit and Grass nim game