• UOJ743 【ZJOI2022】面条 【观察,FFT】


    给定长为 \(n\) 的非负整数序列 \(a_1,\cdots,a_n\) 和正整数 \(x\),每次操作同时令 \(a_i:=a_{\lceil i/2\rceil}+a_{n-\lceil i/2\rceil+1}\)

    \(q\) 次询问非负整数 \(k\) 表示求 \(k\) 次操作后的 \(2^{-k}a_x\bmod 998\,244\,353\) 的值。

    \(T\le 10\) 组数据,\(\sum n\le 2\cdot 10^6\)\(\sum q\le 5\cdot 10^7\)\(k\le 10^{18}\)\(x\le n\)\(a_i<998\,244\,353\)\(2\mid n\)\(k\) 独立均匀随机生成。

    注意到操作一次之后 \(a_{2i-1}=a_{2i}\),设 \(k=\nu_2(n)\),打表可知操作 \(i\ge k+1\) 次后变为 \(m=\lfloor n/2^{k+1}\rfloor\) 个数分别重复 \(2^{k+1}\) 次,最后 \(1\) 个数重复 \(2^k\) 次。

    设这些数是 \(c_0,\cdots,c_m\),则操作后变为 \(c_0+c_m,c_0+c_{m-1},c_1+c_{m-1},\cdots,2c_{\lfloor m/2\rfloor}\)

    设差分数组是 \(d_1,\cdots,d_m\),则操作后变为 \(-d_m,d_1,\cdots,(-1)^md_{\lceil m/2\rceil}\),可以看作 \((d_1,d_2,\cdots,d_m,-d_m,-d_{m-1},\cdots,-d_1)\) 的置换,其将位置 \(i\) 映至 \(2i\bmod(2m+1)\),从而每个循环长度都是 \(r=\text{ord}_{2m+1}(2)\) 的因数。

    然后我们还已知所有元素之和 \(S\) 每次变为 \(2\) 倍,解方程可知 \(2^{-k}c_x=\frac S{2m+1}+2^{-k}\sum_{i=1}^m(\frac{2i}{2m+1}-[i>x])d_{2^{-k}i}\)

    对于后面这个和式,可以对每个循环用卷积预处理出每个 \(k\) 的答案,时间复杂度 \(\mathcal O(n\text d(n)+q)\)

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef std::pair<int, int> pii;
    const int N = 1 << 21, M = 1 << 15, mod = 998244353;
    int pw2[M + 1], pw2b[M];
    int pwi(int x){return (LL)pw2b[x >> 15] * pw2[x & (M - 1)] % mod;}
    int ksm(int a, int b){
    	int res = 1;
    	for(;b;b >>= 1, a = (LL)a * a % mod)
    		if(b & 1) res = (LL)res * a % mod;
    	return res;
    }
    void qmo(int &x){x += x >> 31 & mod;}
    int test, T;
    ULL seed;
    ULL rd(){return seed ^= (seed << 13), seed ^= (seed >> 7), seed ^= (seed << 17);}
    int n, q, x, a[N], ans[25], hah[N], ord;
    LL kmax;
    void work(){
    	static int b[N >> 1];
    	for(int i = 0;i < (n >> 1);++ i) qmo(b[i] = a[i] + a[n - i - 1] - mod);
    	for(int i = 0;i < (n >> 1);++ i) a[i << 1] = a[i << 1 | 1] = b[i];
    }
    int lim, rev[N << 1], w[2][N << 1];
    void calrev(int len){
    	int L = -1; lim = 1; while(lim <= len){lim <<= 1; ++ L;}
    	for(int i = 1;i < lim;++ i) rev[i] = rev[i >> 1] >> 1 | ((i & 1) << L);
    }
    void NTT(int *A, bool op){
    	for(int i = 0;i < lim;++ i)
    		if(i < rev[i]) std::swap(A[i], A[rev[i]]);
    	for(int md = 1;md < lim;md <<= 1)
    		for(int i = 0;i < lim;i += md << 1)
    			for(int j = 0;j < md;++ j){
    				int y = (LL)A[i + j + md] * w[op][md + j] % mod;
    				qmo(A[i + j + md] = A[i + j] - y);
    				qmo(A[i + j] += y - mod);
    			}
    	if(op){
    		int iv = ksm(lim, mod - 2);
    		for(int i = 0;i < lim;++ i) A[i] = (LL)A[i] * iv % mod;
    	}
    }
    int A[N << 1], B[N << 1], tmp[N];
    std::vector<pii> cyc;
    bool vis[N];
    void solve(){
    	cyc.clear();
    	std::cin >> n >> q >> x >> kmax; -- x;
    	for(int i = 0;i < n;++ i) std::cin >> a[i];
    	int lg = __builtin_ctz(n);
    	for(int i = 0;i <= lg;++ i){
    		ans[i] = a[x]; work();
    	}
    	ans[lg + 1] = a[x];
    	int m = n >> (lg + 1);
    	LL Ans = 0;
    	if(!m){
    		for(int i = 1;i <= q;++ i){
    			LL k = rd() % kmax;
    			if(k > lg) k = lg;
    			Ans ^= (LL)ans[k] * pwi(k) % mod * i;
    		}
    		std::cout << Ans << '\n';
    		return;
    	}
    	x >>= lg + 1;
    	for(int i = 0;i <= m;++ i) a[i] = a[i << (lg + 1)];
    	int avg = 0;
    	for(int i = 0;i < m;++ i) qmo(avg += a[i] - mod);
    	int iv = ksm(m << 1 | 1, mod - 2);
    	avg = (2ll * avg + a[m]) * iv % mod * pwi(lg + 1) % mod;
    	for(int i = m;i;-- i){
    		qmo(a[i] -= a[i - 1]);
    		qmo(a[2 * m - i + 1] = -a[i]);
    	}
    	int md = m << 1 | 1;
    	memset(vis, 0, md);
    	for(int i = 1;i < md;++ i) if(!vis[i]){
    		vis[i] = true;
    		int l = 1, x = i << 1;
    		if(x >= md) x -= md;
    		while(x != i){
    			vis[x] = true; ++ l;
    			x <<= 1; if(x >= md) x -= md;
    		}
    		cyc.emplace_back(l, i);
    	}
    	sort(cyc.begin(), cyc.end());
    	ord = cyc.back().fi;
    	memset(hah, 0, ord << 2);
    	for(int i = 0, j = 0;i < (int)cyc.size();i = j){
    		int len = cyc[i].fi;
    		memset(tmp, 0, len << 2);
    		while(j < (int)cyc.size() && len == cyc[j].fi) ++ j;
    		calrev(len << 1);
    		for(int $ = i;$ < j;++ $){
    			int now = cyc[$].se;
    			memset(A, 0, lim << 2);
    			memset(B, 0, lim << 2);
    			for(int k = 0;k < len;++ k){
    				if(now <= m) A[k] = 2ll * now * iv % mod - (now > x);
    				B[len - k] = a[now];
    				now <<= 1; if(now >= md) now -= md;
    			}
    			NTT(A, 0); NTT(B, 0);
    			for(int k = 0;k < lim;++ k) A[k] = (LL)A[k] * B[k] % mod;
    			NTT(A, 1);
    			for(int k = 0;k < len;++ k){
    				qmo(tmp[k] += A[k] - mod);
    				qmo(tmp[k] += A[k + len] - mod);
    			}
    		}
    		for(int $ = 0;$ < ord;$ += len)
    			for(int k = 0;k < len;++ k)
    				qmo(hah[$ + k] += tmp[k] - mod);
    	}
    	for(int i = 1;i <= q;++ i){
    		LL k = rd() % kmax;
    		if(k <= lg + 1) Ans ^= (LL)ans[k] * pwi(k) % mod * i;
    		else Ans ^= (avg + (LL)hah[(k - lg - 1) % ord] * pwi(k % (mod - 1))) % mod * i;
    	}
    	std::cout << Ans << '\n';
    }
    int main(){
    	std::ios::sync_with_stdio(0);
    	std::cin >> test >> T >> seed; *pw2 = *pw2b = 1;
    	for(int i = 1;i <= M;++ i) pw2[i] = (pw2[i - 1] + (pw2[i - 1] & 1) * mod) >> 1;
    	for(int i = 1;i < M;++ i) pw2b[i] = (LL)pw2b[i - 1] * pw2[M] % mod;
    	for(int md = 1;md <= N;md <<= 1){
    		int Wn = ksm(3, (mod - 1) / (md << 1));
    		w[0][md] = w[1][md] = 1;
    		for(int i = 1;i < md;++ i) w[0][md + i] = (LL)w[0][md + i - 1] * Wn % mod;
    		for(int i = 1;i < md;++ i) w[1][md + i] = mod - w[0][(md << 1) - i];
    	}
    	while(T --) solve();
    }
    
  • 相关阅读:
    IOS 开发者账号 (team账号)
    我能否把一个开发者帐号下的app转移到另一个开发者帐号下面?
    Xcode清楚缓存、清理多余证书
    CABasiAnimation的变化属性
    CATransform3DMakeRotation注意
    绘图详解(转摘)
    iOS开发UI篇—核心动画(UIView封装动画)(转摘)
    iOS开发UI篇—核心动画(转场动画和组动画)(转摘)
    iOS开发UI篇—核心动画(关键帧动画)(转摘)
    iOS开发UI篇—核心动画(基础动画)
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/16307042.html
Copyright © 2020-2023  润新知