zoukankan      html  css  js  c++  java
  • [AGC034F]RNG and XOR

    题目

      点这里看题目。

    分析

      第一步可以将(A)数组转化成概率(P(j)):每一步操作异或(j)的概率。
      接着发现,(x)(0)变成(i)的期望等于(x)(i)变成(0)的期望。
      这样我们的起点虽然不一样,但是终点就是一样的。这样我们可以套用随机游走的模型:
      (f(i)):从(i)为起点变成(0)的期望。
      边界条件为(f(0)=0),剩下的转移为:

    [egin{aligned} &f(i)=1+sum_{j=0}^{2^n-1}P(j)f(ioplus j)\ Rightarrow&f(i)=1+sum_{joplus k=i}P(j)f(k)\ Rightarrow&f(i)-1=sum_{joplus k=i}P(j)f(k) end{aligned} ]

      我们发现(f)是一个类似 " 自己卷自己 " 的转移。但是却又不太一样,因为多了 -1 的常数。
      我们还是把它写成卷积的形式:

    [(f(0),f(1),f(2),...,f(2^n-1))igoplus(P(0),P(1),P(2),...,P(2^n-1))=(?,f(1)-1,f(2)-1,...,f(2^n-1)-1) ]

      发现我们不能确定卷起来的第 0 项是多少,因为我们的转移的边界是(f(0)=0)
      但是我们设卷出来的第 0 项为(x),则可以得到:

    [egin{aligned} x+sum_{i=1}^{2^n-1}(f(i)-1) &=sum_{i=0}^{2^n-1}sum_{joplus k=i}P(j)f(k)\ &=sum_{i=0}^{2^n-1}f(i)sum_{j=0}^{2^n-1}P(j)\ &=sum_{i=0}^{2^n-1}f(i) end{aligned} ]

      也就是说,我们卷出来的东西应该和原来的(f)的和是一样的。
      然后可以得到(x=f(0)+2^n-1)

    [(f(0),f(1),f(2),...,f(2^n-1))igoplus(P(0),P(1),P(2),...,P(2^n-1))=(f(0)+2^n-1,f(1)-1,f(2)-1,...,f(2^n-1)-1) ]

      我们发现(f)向量和结果向量比较像,并且有公共部分,就可以考虑碱法:

    [(f(0),f(1),f(2),...,f(2^n-1))igoplus(P(0)-1,P(1),P(2),...,P(2^n-1))=(2^n-1,-1,-1,...,-1) ]

      这样我们就可以用 FWT 变换之后求出(f)向量来。
      但是我们发现 FWT 之后会出现第 0 项上都是 0 的情况,此时不能求逆元。
      不过,同时(f(0))的变换后的值(f'(0))也是毫无限制的。因此我们可以给(f'(0))带入任意值,比如(0)。逆变换后第 0 项为(k)(f)中每一项就都会多贡献(k),减掉就好。

    代码

    #include <cstdio>
    
    const int mod = 998244353, inv2 = 499122177;
    const int MAXN = 20, MAXL = ( 1 << 18 ) + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    int F[MAXL], p[MAXL], h[MAXL];
    int N, len;
    
    int qkpow( int base, int indx )
    {
    	int ret = 1;
    	while( indx )
    	{
    		if( indx & 1 ) ret = 1ll * ret * base % mod;
    		base = 1ll * base * base % mod, indx >>= 1;
    	}
    	return ret;
    }
    
    int inv( const int a ) { return qkpow( a, mod - 2 ); }
    int fix( const int x ) { return ( x % mod + mod ) % mod; }
    
    void FWT( int *f, const int mode )
    {
    	int t1, t2;
    	for( int s = 2 ; s <= len ; s <<= 1 )
    		for( int i = 0, t = s >> 1 ; i < len ; i += s )
    			for( int j = i ; j < i + t ; j ++ )
    			{
    				t1 = f[j], t2 = f[j + t];
    				if( mode > 0 ) f[j] = ( t1 + t2 ) % mod, f[j + t] = fix( t1 - t2 );
    				else f[j] = 1ll * ( t1 + t2 ) * inv2 % mod, f[j + t] = 1ll * fix( t1 - t2 ) * inv2 % mod;
    			}
    }
    
    int main()
    {
    	int s = 0;
    	read( N ); len = 1 << N;
    	for( int i = 0 ; i < len ; i ++ ) read( p[i] ), s = ( s + p[i] ) % mod;
    	s = inv( s );
    	for( int i = 0 ; i < len ; i ++ ) p[i] = 1ll * p[i] * s % mod;
    	for( int i = 1 ; i < len ; i ++ ) h[i] = mod - 1;
    	h[0] = len - 1, p[0] = fix( p[0] - 1 );
    	FWT( h, 1 ), FWT( p, 1 );
    	for( int i = 1 ; i < len ; i ++ ) F[i] = 1ll * h[i] * inv( p[i] ) % mod;
    	FWT( F, -1 );
    	int tmp = mod - F[0];
    	for( int i = 0 ; i < len ; i ++ ) write( ( tmp + F[i] ) % mod ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    MyEclipse修改Servlet模板
    AndroidStudio启动时不自动打开项目
    Android Studio启动时出现unable to access android sdk add-on list
    基础概述
    Java环境变量设置
    eclipse安装adt插件
    设置一个.exe文件开机启动
    笔记本玩游戏设置全屏
    记一次服务器病毒查杀过程:lsass.exe占用内存高
    LayUI制作日历工作记录簿
  • 原文地址:https://www.cnblogs.com/crashed/p/12592760.html
Copyright © 2011-2022 走看看