zoukankan      html  css  js  c++  java
  • CF1573D D. Xor of 3 | 2500

    很不错的一道构造

    题目传送门


    题意

    给定一个01序列, 每次可以选择相邻的三个数, 将他们异或起来, 并让这三个数都等于异或结果。
    每次操作用一个数x表示, 表示将x, x+1, x+2 异或起来
    求一个长度不超过n的操作序列使得序列中每个数都等于0, 或者输出无解
    保证只要能让所有数都等于0, 则存在合法操作序列

    题解

    首先我们考虑有奇数个1, 那么显然无解
    这时候我们考虑从第一个1开始, 每次消掉第一对1(最前面两个1)
    --这时候对于每一对1分两种情况

    -- · 中间有奇数个0
    比如10001、101 , 这种可以直接消掉
    假设第一个1位置为x, 那么可以进行x, x+2, x+4....., 使得变成中间只有一个0
    10001 -> 11101
    然后消掉最后三个, 再一直往前消即可。

    -- · 中间有偶数个0
    这种显然无法直接整个消掉, 可以让他先全部变成1, 这时候如果左边或右边有一个0, 就可以消掉, 否则无解
    比如1001 -> 1111 假设 原序列是10010, 右边有一个0, 那么现在11110可以消掉


    实现

    还是不好实现的,这里给出我的实现

    如果第一个数是0, 直接往后消, 奇数直接消, 偶数前面有0能消
    否则第一个数是1, 如果第一对是奇数情况, 直接消掉, 变第一种情况
    否则第一对是偶数, 暂时不管第一对, 先把后面的消了, 这时候后面就有了0, 再消第一对
    如果后面消不掉, 那么显然无解

    具体不懂看代码
    solve(x) 表示将x及以后的全消掉, return1表示能消掉, 否则不能.

    **#include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    
    int read(){
    	int num=0, flag=1; char c=getchar();
    	while(!isdigit(c) && c!='-') c=getchar();
    	if(c=='-') flag=-1, c=getchar();
    	while(isdigit(c)) num=num*10+c-'0', c=getchar();
    	return num;  
    }
    
    const int N = 200505;
    int T, n;
    int a[N], nex[N];
    
    vector<int> ans;
    int solve(int x){
    	if(x > n) return 0;
    	if(nex[x] == 0) return 1;
    	if( a[x] == 0 || (nex[x]-x-1)%2 ){
    		if(a[x]==0) x = nex[x];
    		while(x){
    			if((nex[x]-x-1)%2){
    				int i;
    				for(i=x; i+2<nex[x]; i+=2){
    					ans.push_back(i);
    				}
    				for(; i>=x; i-=2){
    					ans.push_back(i);
    				}
    				
    			}else{
    				for(int i=x; i+2<nex[x]; i+=2){
    					ans.push_back(i);
    				}
    				for(int i=x-1; i+2<=nex[x]; i+=2){
    					ans.push_back(i);
    				}
    			}
    			
    			x = nex[nex[x]];
    		}return 1;
    	}else{
    		if(solve(nex[x]+1)){
    			for(int i=x; i+2<nex[x]; i+=2){
    					ans.push_back(i);
    			}
    			for(int i=nex[x]+1; i-2>=x; i-=2){
    				ans.push_back(i-2);
    			}
    			return 1;
    		}else return 0;
    	}
    }
    
    int main(){
    	T=read();
    	while(T--){
    		n = read();
    		for(int i=1; i<=n; i++) a[i] = read();
    		int las = 0;
    		int cnt = 0;
    		for(int i=n; i>=1; i--){
    			nex[i] = las;
    			if(a[i]) las = i, cnt++;
    		}
    		if(cnt % 2) {
    			printf("NO
    ");
    			continue;
    		}
    		ans.clear();
    		if(solve(1)){
    			printf("YES
    %d
    ", ans.size());
    			for(int i=0; i<ans.size(); i++) {
    				printf("%d ", ans[i]);
    			}printf("
    ");
    		} else printf("NO
    ");
    	}
    	return 0;
    }
    **
    
  • 相关阅读:
    windows下区块链,私有链搭建详细教程(图文详解)
    MySQL 5.7 mysqldump的Bug导致复制异常
    关于MySQL 5.6 DDL阻塞DML的问题!
    mysqldump 根据时间字段导出数据的问题
    MySQL undo redo
    InnoDB undo, redo,binlog,data什么时候写?
    MySQL master 宕机导致slave数据比master多的case
    Jboss配置自动重连数据库
    星爷001正式开始写blog啦
    本地及远程二级缓存
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/15324535.html
Copyright © 2011-2022 走看看