zoukankan      html  css  js  c++  java
  • HAOI2015 数组游戏

    P3179 [HAOI2015]数组游戏 [* medium]

    给定 (n) 个硬币,多次查询,每次给定 (w) 表示有 (w) 枚硬币正面朝上(具体位置给定),每次操作为:

    1. 选择一面正面朝上的硬币并翻转,然后假设其下标为 (x),此时你可以翻转 (x,2x...kx(kxle n))

    求先手后手谁会 win,(nle 10^9,q,wle 100)

    Solution

    首先有一个我不会的结论,但是论证并不是很难,若干枚硬币组成的游戏的 SG 值就是各个硬币的 SG 值的异或和。

    论证的话考虑翻转一枚硬币并当作子结论处理,由于翻硬币中消去一个元素与对游戏的 SG 值异或上相同的 SG 值等价,所以不难看出 SG 定理的成立。

    知道这个后这个题就很 easy 了。

    不难注意到,对于 (x) 这枚硬币而言,我们计算的 SG 值等价于将 (x) 视为 (1) 号硬币,然后考虑总共有 (lfloorfrac{n}{x} floor) 枚硬币下的情况。

    考虑对于某个 (lfloorfrac{n}{x} floor) 如何快速的计算答案,等价于将此情况下 (2,3...m) 的 SG 值异或起来的 ( m mex)

    由于结论仍然是生效的,此时只需要考虑 (frac{n}{xt}) 的形式,从小到大枚举 (frac{n}{xt}) 并根据奇偶性判断能否对后续产生影响(加入肯定是可以加入的),对于每次我们计算一次 ( m mex),不难注意到 ( m mex) 的上界是 (sqrt{frac{n}{x}}) 的级别,所以直接暴力找 mex 就可以了。

    于是我们可以在 (mathcal O(n^{frac{3}{4}})) 的时间复杂度解决这个问题。

    • (sum sqrt{frac{n}{x}}le int sqrt{x}+int sqrt{frac{n}{x}}=n^{frac{3}{4}})

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 1e5 + 5 ; 
    int n, cnt, top, num, v1[N], v2[N], sg[N], f[N], g[N], mx[N] ; 
    struct node {
    	int len, w ; 
    	node(int _len = 0, int _w = 0) { len = _len, w = _w ; }
    } st[N] ;
    int Get(int x) { return (x <= cnt) ? f[x] : g[n / x] ; }
    void add(int x) { mx[x] = 1, sg[++ num] = x ; }
    void dec(int x) { mx[x] = 0 ; }
    void dfs(int x) {
    	if( x <= cnt && v1[x] ) return ; 
    	if( x > cnt && v2[n / x] ) return ; 
    	(x <= cnt) ? v1[x] = 1 : v2[n / x] = 1 ; 
    	for(re int l = 2, r; l <= x; l = r + 1) 
    		r = x / (x / l), dfs(x / l) ;
    	top = 0 ; 
    	for(re int l = 2, r; l <= x; l = r + 1) 
    		r = x / (x / l), st[++ top] = node((r - l + 1), Get(x / l)) ;
    	int sf = 0, u = 1 ; 
    	for(re int j = 1; j <= top; ++ j) {
    		add(sf ^ st[j].w) ;
    		if( st[j].len & 1 ) sf ^= st[j].w ; 
    	} 
    	while( mx[u] ) ++ u ; 
    	(x <= cnt) ? f[x] = u : g[n / x] = u ;
    	while( num ) dec(sg[num]), -- num ; 
    }
    signed main()
    {
    	n = gi(), cnt = sqrt(n) ; 
    	f[1] = 1, v1[1] = 1, dfs(n) ; 
    	int q = gi() ; 
    	while( q-- ) {
    		int w = gi(), SG = 0, x ; 
    		while( w-- ) x = gi(), SG ^= Get(n / x) ; 
    		( !SG ) ? puts("No") : puts("Yes") ; 
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    HDU1412:{A} + {B}
    [置顶] 写好最简单的冒泡排序
    python scrapy 基础
    hdu2531之BFS
    Direct3D 11的流水线
    Direct3D 11的资源
    Perl 多线程模块 Parallel::ForkManager
    POJ 3450 Corporate Identity (KMP+暴搞)
    hdu 2853
    我所理解的设计模式(C++实现)——中介者模式(Mediator Pattern)
  • 原文地址:https://www.cnblogs.com/Soulist/p/13861601.html
Copyright © 2011-2022 走看看