【思考】CF1747D_Yet Another Problem
感慨:吹爆CF评测机的RE检测功能,要不一晚上也调不出来这个睿智错误(把oddmin和evenmin开成了数组)
题目链接:https://codeforces.com/contest/1747/problem/D
题意:给定一个长度为 $n$ 的序列 $A_1, A_2, ... A_n$,共有 $q$ 次询问,每次给定一组 $l$ 和 $r$,可以无限次进行以下操作:自选长度为奇数的 $[l,r]$ 的子区间 $[L,R]$,将 $A_L, A_{l+1}, ... ,A_R$ 的值统一变更为 $A_L \oplus A_{L+1} \oplus ... \oplus A_R$。询问使得 $A_L, A_{L+1}, ... ,A_R$ 全部为 $0$ 的最少操作次数,若无法做到输出 $-1$。
思路:观察到如下性质:
1. 因为操作的序列长度为奇数,每次操作后区间的异或和不变。
2. 基于1,如果原来区间的异或和不为零,那么就一定不可能。
随后考虑如何操作:
1. 如果原本区间为全 $0$,则不需要操作。
2. 如果区间长度为奇数,那么操作一次就可以。
3. 如果区间长度为偶数,并且头尾至少有一个为零,那么就可以把那个零扔掉,转化为情况2,操作一次即可(当时主要是卡在这里了)。
下面考虑区间长度为偶数,且头尾均不为零的情况:
如果 $\exists l \le p \le r$ $s.t.$ $A_L \oplus A_{L+1} \oplus ... \oplus A_p=0$ 且 $p-l+1$ 为奇数,那么就可以进行 $[l,p]$ 和 $[p+1,r]$ 两次操作使得区间全零。
如果这样的 $p$ 不存在,那么 $A_L$ 永远都不可能为零,输出 $-1$。
下面考虑如何判断这样的 $p$ 是否存在。官方题解貌似使用了和我不一样的解法:
使用 $suc$ 数组存储一个数后面的第一个可以使这段区间异或和为零,且区间长度为奇数的位置(如果本身为$0$可以是他自己),如果不存在就为inf。比如对于 $A=[3,0,3,1,2,3]$,对应的 $suc=[3,2,5,6,inf,inf]$。如果 $suc_l \le r$,那么就说明这样的 $p$ 存在。
为了生成 $suc$ 数组,可以倒序循环,用两个 $map$ 分别记录奇数位和偶数位上,上一个后缀异或和等于该数的位置。比如上面的 $A$,当全部循环结束后,奇数的 $map$ 中,$map[0]=1, map[1]=5, map[3]=3$ (注意 $map[3]\neq 2$ 因为这个 $map$ 是奇数的,$i$ 为偶数时不更新)。这样循环到 $i$ 时,如果 $i$ 是奇数,就在偶数的 $map$ 里找有没有 $sufxor_i$,找到了记为 $suc_i$,找不到 $suc_i$ 就记为 $inf$。然后更新一下奇数的 $map_{sufxor_i}=i$ 就行。注意一下边界条件,根据 $n$ 的奇偶性把对应的 $map_0$ 的初始值设为 $n+1$。
代码:
#include <bits/stdc++.h>
//#include <windows.h>
#define index xedni
#define bug cout<<"bug "<<__LINE__<<endl
const int MOD=1e9+7;
const int inf=1e9+7;
const int MAXN=200050;
using namespace std;
int n,q,a[MAXN],sufxor[MAXN];
long long sufsum[MAXN];
int suc[MAXN];
map<long long,int> oddmin,evenmin;
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin.tie(0); cout.tie(0);
ios_base::sync_with_stdio(false);
cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i];
if(n%2) evenmin[0]=n+1;
else oddmin[0]=n+1;
for(int i=n;i>=1;i--)
sufsum[i]=1ll*a[i]+sufsum[i+1],
sufxor[i]=a[i]^sufxor[i+1];
for(int i=n;i>=1;i--)
{
if(i%2)
{
if(!evenmin[sufxor[i]]) suc[i]=inf;
else suc[i]=evenmin[sufxor[i]]-1;
oddmin[sufxor[i]]=i;
}
else
{
if(!oddmin[sufxor[i]]) suc[i]=inf;
else suc[i]=oddmin[sufxor[i]]-1;
evenmin[sufxor[i]]=i;
}
if(!a[i]) suc[i]=i;
}
while(q--)
{
int l,r; cin>>l>>r;
if(!(sufsum[l]-sufsum[r+1])) { cout<<0<<endl; continue; }
if((sufxor[l]^sufxor[r+1])) { cout<<-1<<endl; continue; }
if((l-r+1)%2)
cout<<1<<endl;
else
{
if(!a[l] || !a[r]) { cout<<1<<endl; continue; }
if(suc[l]>r) cout<<-1<<endl;
else cout<<2<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号