• CF1119H Triple


    CF1119H Triple [* hard]

    给定 (n,k),以及 (n) 个三元组 ((a_i,b_i,c_i)),常数 (x,y,z) 表示每个三元组均有 (x)(a_i)(y)(b_i)(z)(c_i),求从每个数组中选出一个数使得异或和为 (tin [0,2^k)) 的方案数。

    保证 (a_i,b_i,c_i<2^k,nle 10^5,kle 17)

    ( m Sol:)

    首先可以 (mathcal O(n2^kk)) 的做 FWT

    然后众所周知 (c(i,j)=(-1)^{i& j}),每个元素都形如 (f_1 imes x^{a_i}+f_2 imes x^{b_i}+f_3 imes x^{c_i}) 这样的一个集合幂级数,可能的 FWT 值仅有 (8) 种,如果能对每个点值 (x) 算出取值数就可以知道答案了。

    然后考虑一个极其巧妙的转换,不妨给所有三元组均异或上 (a_i) 然后视为 ((0,a_ioplus b_i,a_ioplus c_i)) 这样的三元组,这样考虑 FWT 点值必然形如 (f_1+f_2 imes (-1)^{i&(...)}+f_3 imes (-1)^{i&(...)})

    于是 FWT 数组有且仅有 (4) 种点值 ((f_1+f_2+f_3,f_1-f_2-f_3,f_1+f_2-f_3,f_1-f_2+f_3)),分别设为 ((a,b,c,d))

    于是只需要考虑列出 (4) 个方程来求解这 (4) 个点值的数量(黎明前的巧克力)

    • (c_1+c_2+c_3+c_4=n)

    事实上,我们进行分类讨论:

    • (c_1)(b)(c) 取值均为 (1) 的数量。
    • (c_2)(b)(c) 取值均为 (-1) 的数量。
    • (c_3)(b) 取值为 (1)(c) 取值为 (-1) 的数量。
    • (c_4)(b) 取值为 (-1)(c) 取值为 (1) 的数量。

    于是将上值加起来做 FWT 得到的结果应该是 (c_1+c_3-c_2-c_4)

    (c) 处取值设为 (1),那么 FWT 得到的结果应该是 (c_1+c_4-c_2-c_3) 的值。

    然后最后最为巧妙的是,我们令 (boplus c)(1)

    这样得到的结果显然就是 (c_1+c_2-c_3-c_4)

    于是设我们得到的值分别为 (A,B,C,D),那么就有:

    [egin{cases} c_1+c_2+c_3+c_4=A \c_1-c_2+c_3-c_4=B \c_1-c_2-c_3+c_4=C \c_1+c_2-c_3-c_4=D end{cases}]

    解得:

    [egin{cases} c_1=frac{A+B+C+D}{4} \c_2=frac{A+D-B-C}{4} \c_3=frac{A+B-C-D}{4} \c_4=frac{A+C-B-D}{4} end{cases}]

    然后我们进行 IFWT 即可得到答案。

    最后这一步考虑正负来计数实在是 tql !

    综上,我们得到了一个 (mathcal O(k2^k+n)) 的优秀做法辣!

    (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
    #define int long long
    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 P = 998244353 ; 
    const int IP = 499122177 ;
    const int N = 1e5 + 5 ; 
    const int M = 3e5 + 5 ; 
    int n, f1, f2, f3, f4, limit, fA, f[M] ;
    struct node { int x, y ; } c[N] ;
    struct fucti { int a1, a2, a3, a4 ; } g[M] ;
    int fpow( int x, int k ) {
    	int ans = 1, base = x ; 
    	while(k) {
    		if(k & 1) ans = ans * base % P ; 
    		base = base * base % P, k >>= 1 ; 
    	} return ans ; 
    }
    void FWT( int *a, int type ) {
    	for( re int k = 1; k < limit; k <<= 1 ) 
    	for( re int i = 0; i < limit; i += ( k << 1 ) ) 
    	for( re int j = i; j < i + k; ++ j ) {
    		int nx = a[j], ny = a[j + k] ;
    		a[j] = (nx + ny) % P, a[j + k] = (nx - ny + P) % P ; 
    		if( !type ) a[j] = a[j] * IP % P, a[j + k] = a[j + k] * IP % P ;  
    	}
    }
    void init() {
    	memset( f, 0, sizeof(f) ) ; 
    } 
    void Mod( int &x ) {
    	x += P, x += P, x %= P ; 
    }
    signed main()
    {
    	n = gi(), limit = gi(), limit = 1 << limit ; int x, y, z ; 
    	
    	x = gi(), y = gi(), z = gi() ; 
    	f1 = x + y + z, f2 = x - y - z, f3 = x + y - z, f4 = x - y + z ; 
    	Mod(f1), Mod(f2), Mod(f3), Mod(f4) ; 
    	rep( i, 1, n ) {
    		x = gi(), y = gi() ^ x, z = gi() ^ x, fA ^= x ; 
    		c[i].x = y, c[i].y = z ; 
    	}
    	
    	
    	
    	rep( i, 1, n ) ++ f[c[i].x] ; FWT( f, 1 ) ; 
    	for( re int i = 0; i < limit; ++ i ) g[i].a1 = n, g[i].a2 = f[i] ;
    
    	init() ; rep( i, 1, n ) ++ f[c[i].y] ; FWT( f, 1 ) ; 
    	for( re int i = 0; i < limit; ++ i ) g[i].a3 = f[i] ;
    	
    	init() ; rep( i, 1, n ) ++ f[c[i].x ^ c[i].y] ; FWT( f, 1 ) ; 
    	for( re int i = 0; i < limit; ++ i ) g[i].a4 = f[i] ;
    	int ip = IP * IP % P ; 
    	for( re int i = 0; i < limit; ++ i ) {
    		int A = g[i].a1, B = g[i].a2, C = g[i].a3, D = g[i].a4 ; 
    		int c1 = A + B + C + D, c2 = A + D - B - C,
    			c3 = A + B - C - D, c4 = A + C - B - D ;
    		Mod(c1), Mod(c2), Mod(c3), Mod(c4),
    		c1 = c1 * ip % P, c2 = c2 * ip % P, c3 = c3 * ip % P, c4 = c4 * ip % P,
    		f[i] = fpow( f1, c1 ) * fpow( f2, c2 ) % P * fpow( f3, c3 ) % P * fpow( f4, c4 ) % P ;  
    	}
    	FWT( f, 0 ) ; 
    	for( re int i = 0; i < limit; ++ i ) printf("%lld ", f[fA ^ i] ) ; 
    	return 0 ;
    }
    
  • 相关阅读:
    CF261E Maxim and Calculator
    USACO Section 2.1
    码工新人的成长升职之路~
    Skip level 1 on 1
    有效利用1 on 1
    [职场感言] 入职一年总结
    职场新人建议
    L1 正则为什么会使参数偏向稀疏
    Inception网络
    ResNet
  • 原文地址:https://www.cnblogs.com/Soulist/p/13675307.html
Copyright © 2020-2023  润新知