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 ;
    }
    
  • 相关阅读:
    zoj 2316 Matrix Multiplication 解题报告
    BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告
    codeforces 463C. Gargari and Bishops 解题报告
    codeforces 463B Caisa and Pylons 解题报告
    codeforces 463A Caisa and Sugar 解题报告
    CSS3新的字体尺寸单位rem
    CSS中文字体对照表
    引用外部CSS的link和import方式的分析与比较
    CSS样式表引用方式
    10个CSS简写/优化技巧
  • 原文地址:https://www.cnblogs.com/Soulist/p/13861601.html
Copyright © 2011-2022 走看看