zoukankan      html  css  js  c++  java
  • 【GDOI2020模拟01.16】划愤(nim积+行列式)

    https://gmoj.net/senior/#contest/show/2989/1

    先考虑n=2时怎么做,打表找规律找了半天找不出来。

    赛后才知道这是nim积。

    定义(x⊗y)(sg(x,y))

    有一坨性质:
    (x,y<2^{2^k},x⊗y<2^{2^k})

    (2^{2^k}⊗2^{2^k}={3 over 2}2^{2^k})

    可以把⊗看做乘法,(⊕)(异或)看做加法,所以还有分配律。

    (x⊗y(x>y)),设(k)为最大的(k)满足(2^{2^k}<=x),设(M=2^{2^k})

    (x=s*M+t=s*M⊕t,y=p*M+q=p*M⊕q)

    (x⊗y=spMM+sMq+tpM+tq)

    (=M(sp+sq+tp)+tq+(M/2⊗sp))

    字母间省略了(⊗)号,(+)号即(⊕)

    递归求出(sp,sq,tp,tq,M/2sp)即可。

    时间复杂度:(O(5^{log~log~V}))

    预处理((0-255,0-255))会快许多。

    题目中重定义加法和乘法,求行列式即可。

    注意行列式要逆元,(v^{-1}=v^{2^{2^k}-2})(满足费马小定理)。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    #define ul unsigned long long
    
    const ul maxM = (ul) 1 << 32;
    const ul a2_63 = (ul) 1 << 63;
    
    const int C = 256;
    
    ul b[C][C];
    
    ul calc2(ul x, ul y) {
    	if(!x || !y) return 0;
    	if(x == 1) return y;
    	if(y == 1) return x;
    	if(x < y) return calc2(y, x);
    	ul M = 2; while(M < maxM && M * M <= x) M *= M;
    	ul p = x / M, q = x % M;
    	ul s = y / M, t = y % M;
    	ul c1 = calc2(p, s), c2 = calc2(p, t) ^ calc2(q, s), c3 = calc2(q, t);
    	return M * (c1 ^ c2) ^ c3 ^ calc2(M / 2, c1);
    }
    
    ul calc(ul x, ul y) {
    	if(x < C && y < C) return b[x][y];
    	if(x < y) swap(x, y);
    	ul M = 2; int k = 1;
    	while(M < maxM && M * M <= x) M *= M, k *= 2;
    	ul p = x >> k, q = x & (M - 1);
    	ul s = y >> k, t = y & (M - 1);
    	ul c1 = calc(p, s);
    	return ((c1 ^ calc(p, t) ^ calc(q, s)) << k) ^ calc(q, t) ^ calc(M / 2, c1);
    }
    
    ul ksm(ul x, ul y) {
    	ul s = 1;
    	for(; y; y /= 2, x = calc(x, x))
    		if(y & 1) s = calc(s, x);
    	return s;
    }
    
    ul qni(ul x) {
    	if(x >= maxM) return ksm(x, (a2_63 - 1) * 2);
    	ul M = 2; while(M <= x) M *= M;
    	return ksm(x, M - 2);
    }
    
    const int N = 155;
    
    int n;
    ul a[N][N];
    
    int main() {
    	freopen("partition.in", "r", stdin);
    	freopen("partition.out", "w", stdout);
    	ff(i, 0, C) ff(j, 0, C) b[i][j] = calc2(i, j);
    	scanf("%d", &n);
    	fo(i, 1, n) fo(j, 1, n) {
    		scanf("%llu", &a[i][j]);
    	}
    	int ye = 1;
    	fo(i, 1, n) {
    		int u = -1;
    		fo(j, i, n) if(a[j][i])
    			u = j;
    		if(u == -1)	{ ye = 0; break;}
    		fo(j, i, n) swap(a[u][j], a[i][j]);
    		ll v = qni(a[i][i]);
    		fo(j, i, n) a[i][j] = calc(a[i][j], v);
    		fo(j, i + 1, n) if(a[j][i]) {
    			v = a[j][i];
    			fo(k, i, n) a[j][k] ^= calc(a[i][k], v);
    		}
    	}
    	pp("%s
    ", ye ? "xiaoDyingle" : "xiaoDwandanle");
    }
    
  • 相关阅读:
    给定一个排序数组,你需要在原地删除重复出现的元素
    OSPF-外部路由
    虚链路
    OSPF域间路由计算,防环
    转 C# 只允许运行一个实例
    转 点击关闭时最小化到任务栏
    C#,int转成string,string转成int
    SQL 查找表名 字段名
    C# *= 运算顺序
    SQL 批量删除表
  • 原文地址:https://www.cnblogs.com/coldchair/p/12203219.html
Copyright © 2011-2022 走看看