2024年7月西大大附中集训记录

7.11

UOJ354 新年的投票

提交答案题。

subtask1

做出来了。考虑你一个人根据当前局面的 0/1 数量哪个更多猜测自己头顶的数字。感觉非常没有道理但是相当优秀。

void solve(){
	freopen("your_answer.out", "w", stdout); 
	int n = 15;
	for(int i = 1; i <= n; i++){
		for(int s = 0; s < (1ll << 14); s++){
			int cnt1 = __builtin_popcount(s);
			int cnt0 = 14 - cnt1;
			int now = cnt1 > cnt0;
			if(now)	cnt1++;
			cout<<cnt1%2;
		}
		endl;
	}
	
}

subtask3

非常有启发性。讲题人不放分值导致我直接去想 subtask2 了/fn

构造如下:对于一个人 \(i\) 如果前面没有出现 0/1 就猜自己头上的数为 1 然后投 \(2^{k-1}\) 票,否则不投票。这样的构造会使得只有左边第一个 1 的票有效。显然只有全 0 的情况会错。

void solve(){
	int n = 15;
	freopen("your_answer3.out", "w", stdout); 
	for(int i = 1; i <= n; i++){
		for(int s = 0; s < (1ll << 14); s++){
			int now = 1;
			bool fl = 1;
			for(int j = 1; j < i; j++){
				if(s & (now)){
					fl = 0;
				}
				now <<= 1;
			}
			if(fl){
				int cnt1 = __builtin_popcount(s);
				if(cnt1 % 2 == 0)	write((1ll << (i - 1)));
				else write(-1 * (1ll << (i - 1)));
				put();
			}else{
				write(0);
				put();
			}
		}
		endl;
	}
	
}

subtask2

有了刚才的启发,这个显得简单了不少。

注意到 \(15 = 1 + 2 + 4 + 8\) 所以考虑把这些人分成人数为 \(2^i\)\(4\) 组。然后把组内的数合想象为一个数进行 sub3 的操作。如果前面的组没有组总的异或和为 1 就猜自己这一组异或和为一然后投一票。否则我们可以通过组内有的投 \(1\) 有的投 \(0\) 把票数抵消掉。相当于投 \(0\) 票。

int bel[MAX], col[MAX];
int le[MAX];

void solve(){
	int n = 15;
	int now = 1, lft = 1;
	for(int i = 1; i <= n; i++){
		bel[i] = now;
		lft--;
		if(lft >= (1ll << (now - 1)) / 2){
			le[i] = 1;
		}else{
			le[i] = 0;
		}
		// write(lft), endl;
		if(!lft){
			now++;
			lft = (1ll << (now - 1));
		}
	}
	// for(int i = 1; i <= n; i++){
		// write(le[i]), put();
	// }endl;
	 freopen("your_answer2.out", "w", stdout); 
	for(int i = 1; i <= n; i++){
		for(int s = 0; s < (1ll << 14); s++){
			int now = 1;
			for(int j = 1; j <= 10; j++)	col[j] = 0;
			for(int j = 1; j < i; j++){
				if(s & (now)){
					col[bel[j]] ^= 1; 
				}
				now <<= 1;
			}
			for(int j = i + 1; j <= n; j++){
				if(s & now){
					col[bel[j]] ^= 1;
				}
				now <<= 1;
			}
			bool fl = 1;
			for(int j = 1; j < bel[i]; j++){
				if(col[j])	fl = 0;
			}
			if(fl){
				int now = 1;
				for(int j = 1; j <= 10; j++){
					if(j == bel[i])	continue;
					now ^= col[j];
				}
				write(now);
			}else{
				write(le[i]);
			}
		}
		endl;
	}
	
}

subtask4

你不会认为我会吧,不会吧。

posted @ 2024-07-11 18:25  WRuperD  阅读(12)  评论(0编辑  收藏  举报

本文作者:DIVMonster

本文链接:https://www.cnblogs.com/guangzan/p/12886111.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

这是一条自定义内容

这是一条自定义内容