• 【题解】 CF1419E Decryption 格雷码+构造


    Legend

    Link ( extrm{to Codeforces})

    Editorial

    考虑分解质因数 (n=prod_{i=0}^{m-1} p_i^{k_i})

    我们不难把某个数字是否分别存在这些质因数状压成二进制数。

    去除了 (1) 之后我们的二进制数的值域是 ((0,2^m)) 的开区间。

    这容易让人想到格雷码,每次只切换一位,并且去除 (0) 之后相邻两项与一定不为 (0)

    所以如果这题把环改成序列,就可以把所有数字按格雷码顺序来构造答案就行了。

    不过是个环,咋办呢?

    我的解决办法是把 (U=2^{m}-1) 到末尾的格雷码翻转,这样全集 (U) 被翻到最末尾,一定可以和头部有交。

    最末尾的被翻到全集的位置,它和前面的交起来,最高位一定是 1。

    除了 (m=2),这样构造都是正确的。我们总能构造出答案为 (0) 的方案。

    现在讨论 (m=2) 的情况。

    如果 (n=pq),其中 (p,q) 均为质数,那么手动暴力枚举可以知道,答案为 (1)

    否则,质因数为 (U) 的数字至少有 2 个,我们只要构造 (1,cdots,1,3,2,cdots,2,3cdots,3) 这样的序列就行了。

    Code

    #include <bits/stdc++.h>
    
    #define debug(...) fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    #define LL long long
    
    const int MX = 1e5 + 23;
    const LL MOD = 998244353;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    std::vector<int> p ,fac[1 << 10] ,code;
    int st[MX * 2];
    
    void solve(){
    	p.clear();
    	code.clear();
    	for(int i = 0 ; i < (1 << 10) ; ++i)
    		fac[i].clear();
    
    	std::vector<int> tmp;
    	int n = read() ,cn;
    	cn = n;
    	for(int i = 2 ; i * i <= cn ; ++i){
    		if(cn % i) continue;
    		p.push_back(i);
    		while(cn % i == 0) cn /= i;
    	}
    	if(cn != 1) p.push_back(cn);
    	for(int i = 1 ; i * i <= n ; ++i){
    		if(n % i == 0){
    			if(i != 1) tmp.push_back(i);
    			if(i * i != n) tmp.push_back(n / i);
    		}
    	}
    	for(int j = 0 ; j < (int)tmp.size() ; ++j)	
    		st[j] = 0;
    	for(int i = 0 ; i < (int)p.size() ; ++i){
    		for(int j = 0 ; j < (int)tmp.size() ; ++j){
    			if(tmp[j] % p[i] == 0) st[j] |= 1 << i;
    		}
    	}
    	for(int i = 0 ; i < (int)tmp.size() ; ++i)
    		fac[st[i]].push_back(tmp[i]);
    
    	if(p.size() == 2u){
    		if(n == p[0] * p[1]){
    			for(int i = 1 ; i <= 3 ; ++i)
    				for(auto j : fac[i])
    					printf("%d " ,j);
    			puts("
    1");
    		}
    		else{
    			for(auto j : fac[1]) printf("%d " ,j);
    			printf("%d " ,*fac[3].rbegin());
    			fac[3].pop_back();
    			for(auto j : fac[2]) printf("%d " ,j);
    			for(auto j : fac[3]) printf("%d " ,j);
    			puts("
    0");
    		}
    	}
    	else{
    		int aim = 0;
    		for(int i = 0 ; i < (int)(1 << p.size()) ; ++i){
    			code.push_back(i ^ (i >> 1));
    			if((i ^ (i >> 1)) == (1 << p.size()) - 1){
    				aim = i;
    			}
    		}
    		std::reverse(code.begin() + aim ,code.begin() + (1 << p.size()));
    		for(int i = 0 ; i < (int)(1 << p.size()) ; ++i)
    			for(int j : fac[code[i]])
    				printf("%d " ,j);
    		puts("
    0");
    	}
    	return ;
    }
    
    int main(){
    	int T = read();
    	while(T--) solve();
    	return 0;
    }
    
  • 相关阅读:
    NOIP2016-2020 复盘
    「笔记」线段树合并/分裂
    「笔记」线性基
    20210628模拟赛解题报告
    「笔记」左偏树
    题解 CF718C Sasha and Array
    一些杂碎的知识点
    20210614 模拟赛
    洛谷 P4249 [WC2007]剪刀石头布
    CF132E Bits of merry old England
  • 原文地址:https://www.cnblogs.com/imakf/p/14725806.html
Copyright © 2020-2023  润新知