首页 > 其他分享 >Codeforces Round 936 (Div. 2) D

Codeforces Round 936 (Div. 2) D

时间:2024-03-23 15:44:49浏览次数:17  
标签:ok int Codeforces 异或 按位 Div 936 就是 贪心

AB没什么好说的
C二分答案,写的还是不够快,但是也很好了。

D的问题有点大。
我好像一直有一个不对的贪心再用,对于二进制的。
就是我会觉得一堆树或起来小于一个数字,这种限制是每个数字都小于那个数字就可以了。
但是实际上这就是一个很明显错误的贪心。
然后另一个反映就是,对于二进制比较的题面,要求小于某个数字,我就会觉得,直接找到最高位的那个1,让这个1变成0,剩下的就可以随便取了。
这并不是充要条件,很少的题目会用到这种东西。
所以这个想法绝大多数的时候都是在干扰我的判断的。
应该注意。

这题,我的想法就是我上面说的第一个问题导致的。

我写了一个trie树优化dp,\(f[i]\)表示到\(i\)点,保证合法时,能够分出的最大段数。
然后如果能够在前面找到一个位置,\(i\)的异或前缀和异或上这个位置的异或前缀和\(\leq x\),就让\(f[i]\)和这个位置的\(f\)值+1取max。
如果\(f[n]\)的值不存在,那就是-1。
很对啊。可惜,如果题目能把或运算改成取max,我这份代码就是标答。
太痛了。

这个高位到低位的贪心在和位运算有关的题目里面很常见。
但是我还是想不到,我觉得很巧妙,有些地方的处理,很可以学习。
我上面说的第二个错误其实就是一个判断的特殊情况,这个不应该被我当作可以解决整道题的方法,而应该只是对于一些子问题的使用方法。trie树里面就很多这个的应用。这题也有。
事实上,这题就是从高位到低位按位贪心,如果对于某个位置,目标数值的二进制表达=0,那就说明我们要异或上一些数字让这一位也是0,否则答案就不成立了。对于这一位,我们只有这一个选择。我们要做的就是让在这一位是1的数字每两个异或起来,因为我们只能一段一段的取,所以就有了一些位置我们不能分段。
如果这一位的x=1,那相当于我们这一维可以随便取了,假如我们这一维取了0,那我们后面不管怎么分段,只要保证了前面我们规定了不能分段的地方没有被断开,也就是那些高位异或起来是0,就可以随便断了,可以直接统计一次答案。
如果我们取了1,那后面就不一定是能随便断的,但是由于这里是1了,也就是这一位就是不会产生不能分段的限制了。直接开始下一位就好了,不需要记录到对后面的限制中去。但是如果要统计答案,这些限制依旧要算上。

这题,这个贪心的方式,我不是没有考虑过,但是我似乎是对按位的理解不够深刻,我总是觉得,如果有两个限制的范围相互交叉,就会直接导致错误。但是其实完全不会啊,如果交叉就都异或起来呗,如果这样导致了第三个这个位置的1进来,那根据我们异或取的规则,这个位置的第4个1一样会进来,如果没有第4个1,这个就不是这个部分需要管的内容了。

为什么我会这么觉得呢?
感觉就是对按位贪心的理解不够深刻。不同位之间的影响完全是不存在的。而且,很重要的是,我需要满足的限制只是他们需要在一起,只要分在了一组,他们的影响就是不存在,并没有什么如果还和什么数字在一起,这一位的影响就会再次出现。
这是一个。。保守的限制?
唉唉。我对这种保守的限制的感觉不够敏感和熟悉,导致我想不到,否决了这个想法。
按位贪心做少了。

应该就是这些问题了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
	char c=getchar();int a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n,x,a[100001],flag[100001];
int main()
{
//	freopen("1.in","r",stdin);
//	freopen("2.out","w",stdout);
	int T=read();
	while(T--)
	{
		n=read(),x=read();
		for(int i=1;i<=n;i++)
		{
			a[i]=read();flag[i]=0;
		}
		int ans=-1;bool fla=0;
		for(int i=30;i>=0;i--)
		{
			int cnt=0;
			int tmp=(x>>i)&1;int ok=0;
			if(tmp==1)
			{
				for(int j=1;j<=n;j++)
				{
					if(((a[j]>>i)&1)==1)ok^=1;
					if(ok==0&&flag[j]==0)cnt++;
				}
				if(ok==0)ans=max(ans,cnt);
			}
			else
			{
				for(int j=1;j<=n;j++)
				{
					if(((a[j]>>i)&1)==1)ok^=1;
					if(ok==1)flag[j]=1;
				}
				if(ok==1)
				{
					fla=1;
					cout<<ans<<endl;
					break;
				}
			}
		}
		if(fla==0)
		{
			int cnt=0;
			for(int i=1;i<=n;i++)if(flag[i]==0)cnt++;
			cout<<max(ans,cnt)<<endl;
		}
	}
	return 0;
}

/*
2
3 6
0 15 8
3 5
12 8 3


*/

写的时候还是理解的不清晰。
其实写起来应该是要很顺畅的才对。

不够熟练?也许?
老师,我太想进步了

标签:ok,int,Codeforces,异或,按位,Div,936,就是,贪心
From: https://www.cnblogs.com/HLZZPawa/p/18091189

相关文章

  • Codeforces Round 936 (Div. 2)
    CodeforcesRound936(Div.2) A.MedianofanArray题意:给一串数字,每次操作可以将一个数字+1,求最少多少次操作使得数组中位数增加思路:分奇偶讨论:1:如果是奇数的话看中间的数字,如果中间的数字只出现过一次,那么次数就是1,否则看从中间位到右边最后出现这个数字的地方看这个数......
  • 如何实现一个div垂直水平居中?
    第一种:定位        第一种思路:父元素relative,子元素absolute,left为50%,top为50%,再给子div设置距左和距上是自身的一半:transform:translate(-50%,-50%)。代码实现:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="......
  • 每日一题 第二十六期 Codeforces Round 936 (Div. 2)
    A.MedianofanArraytimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouaregivenanarrayaa......
  • 每日一题 第二十七期 Codeforces Round 936 (Div. 2)
    B.MaximumSumtimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouhaveanarrayaaaof......
  • CF-936(AB)
    CF-936(已更新:AB)诶……今天还有一个积分赛……自己学科方面也满是坑要补……感觉自己前途一片灰暗/(ㄒoㄒ)/~~A分析只要增大与初始序列中位数的值相同的数,就能在不改变序列顺序的情况下增大中位数的值代码#include<bits/stdc++.h>usingnamespacestd;#defineendl'......
  • Codeforces Round 935 (Div. 3)
    A-SettingupCamp思路:判断c能否填充b让b为3的倍数查看代码voidsolve(){inta,b,c;cin>>a>>b>>c;intans=a+b/3;b%=3;if(b>0&&b+c<3)cout<<-1<<'\n';else{ans+=(b+c+2)/3;c......
  • cfRound935div3--DEFG题解
    ps:这场因为精神状态不佳,又C题题意有点绕,卡题了,头晕找不到错.最后做了两题就溜了.狠狠扣90分..D-SeraphimtheOwl题意:即选一个位置,使得其满足题意。而且在满足题意的基础上,要靠近中心越好,如果满足题意而且靠近中心的距离一样,那么输出前面那个.intcnt0[300005]={0};......
  • CF1920 Codeforces Round 919 (Div. 2)
    B.SummationGame给你\(n\)个数(均大于0),Alice先执行一次删除不超过\(k\)个数,Bob再执行一次把最多\(x\)个数变成相反数.问最后数组的最大和是多少?这题本来是想先让Alice删除\(k\)个数,但显然不太容易得到最优解,因为还有可能撤回Alice的删除操作,再加上Bob的操作.......
  • Codeforces Round 935 (Div. 3)
    A.SettingupCamp#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;voidsolve(){inta,b,c;cin>>a>>b>>c;intres=a+b/3;b%=3;if(b!=0){if(c<3-b){......
  • 1943+1944.Codeforces Round 934 (Div. 1,Div. 2) - sol
    20240321终于差不多把Div1补完了(F当然没补),第一次打Div1,还是出了一些小状况的。唉。没有补Div1F的逆天题,选择放弃。Dashboard-CodeforcesRound934(Div.2)-CodeforcesDashboard-CodeforcesRound934(Div.1)-Codeforces2A.DestroyingBridgesThere......