这种题显然先二进制拆位,显然改的位置显然只有每一段确定的数的开头和结尾,只需要对于每一个可决策位置都尝试一下填1和0,然后取min即可。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=500010; const ll inf=1e15; struct poi{int pos, w;}a[maxn]; int n, m, tot, xor0, xor1; ll sum0, sum1, ans, ans0; inline void read(int &k) { int f=1; k=0; char c=getchar(); while(c<‘0‘ || c>‘9‘) c==‘-‘ && (f=-1), c=getchar(); while(c<=‘9‘ && c>=‘0‘) k=k*10+c-‘0‘, c=getchar(); k*=f; } inline bool cmp(poi a, poi b){return a.pos<b.pos;} int main() { read(n); read(m); for(int i=1;i<=m;i++) read(a[i].pos), read(a[i].w); sort(a+1, a+1+m, cmp); m++; for(int j=0;j<30;j++) { tot=xor0=sum0=xor1=ans0=0; sum1=(a[1].pos==1)?inf:0; for(int i=1;i<=m;i++) { if(a[i].pos-1!=a[i-1].pos) { ans0=min(ans0+sum0, ans0+sum1+1); xor0=sum0=sum1=0; xor1=1; } xor0^=(a[i].w&(1<<j))!=0; xor1^=(a[i].w&(1<<j))!=0; sum0+=xor0; sum1+=xor1; } ans+=ans0<<j; } printf("%lld\n", ans); }