12.02WC模拟题解

T1 海明距离

Description

设有一长度为n的初始每个位置均为0的序列A。再给定一个长度为n的01序列B。
有Q个特殊的区间[li,ri],你可以选择将A中li到ri这些位置都变为1,当然你可以选择不变。
现在你需要最小化A,B的海明距离。即最小化对应数值不同的位置数目。

Input

第一行包括一个整数n。
接下来一行n个整数,描述序列B。
输入一行一个整数Q。
接下来Q行,每行两个整数li,ri 。

Output

输出最小的海明距离。

Sample Input

输入1:
9
0 1 0 1 1 1 0 1 0
3
1 4
5 8
6 7

输入2:
15
1 1 0 0 0 0 0 0 1 0 1 1 1 0 0
9
4 10
13 14
1 7
4 14
9 11
2 6
7 8
3 12
7 13

Sample Output

输出1:
3

输出2:
5

Data Constraint
这里写图片描述

T2 图染色

Description
这里写图片描述
Input

第一行包括两个整数N,M。
接下来M行每行两个整数u,v,代表存在一条里连接 u,v的无向边。可能存在重边自环。

Output

降序输出所有不为0的F(i) 。保留6位小数输出。

Sample Input

输入1:
5 5
1 2
2 5
3 4
4 5
3 5

输入2:
5 4
1 2
2 5
5 4
4 3

Sample Output

输出1:
3.000000
2.000000

输出2:
2.800000
2.200000

Data Constraint

对于20%的数据,n,m<=100
对于40%的数据,n,m<=5000
另外有20%的数据,保证图为一个连通的简单环,且当且仅当|u-v|=1 ,存在u到v的边。
对于100%的数据,n,m<=500000

题解

对于T1,我们可以想一个朴素的dp
在朴素dp之前先说一个东西:
a数组初始为全0,b数组则有0/1,对于一个位置i,当b[i]=0时,选择i位置变1肯定是会增加距离的,当b[i]=1则相反,所以我们预先处理一个前缀和s数组。
这样我们就可以O(1)得到区间贡献啦!!
设f[i,j]表示处理了前i个区间(没有要求必选i),最右端到达j的贡献数。
我们转移的时候发现,i这一维可以省去。
那么我们就可以简化dp
只设f[i],表示处理到的区间中最右端为i的贡献。
为了保证有序,可以先对区间排序。
考虑f[i]怎么转移到f[j]
为了保证转移正确,我们可以强制当且仅当有一个区间[i,j]时才进行转移。
那么转移就是f[j]=max(f[k])+s[j]-s[i-1],这是[i,j] 区间与之前所有区间相离的情况,所以说k的取值范围是[0,i-1]。因为我们处理到[i,j]时[0,i-1]的f值肯定已经全部处理好了,所以开个线段树维护一下就可以log找出k了。
再处理相交情况。
假设[i,j]中之前已经产生贡献的最右端点为x,那么我们的转移就变成了f[j]=f[x]+s[j]-s[x]
我们发现,f[x]-s[x] 也是可以线段树维护的。

var n,i,j,k,l,inf,tot,sum,q,r,v:longint;
t1,t2,next,t,head,f,s:array[0..4000000]of longint;
function max(x,y:longint):longint;
begin
  if x>y then exit(x) else exit(y);
end;
procedure ad(x,y:longint);
begin
  inc(tot);
  next[tot]:=head[x];
  head[x]:=tot;
  t[tot]:=y;
end;
procedure build(root,l,r:longint);
var mid:longint;
begin
  if l=r then begin
    if l=0 then begin
      t1[root]:=0;
      t2[root]:=0;
    end else begin
      t1[root]:=inf;
      t2[root]:=inf;
    end;
    exit;
  end;
  mid:=(l+r)div 2;
  build(2*root,l,mid);
  build(2*root+1,mid+1,r);
  t2[root]:=max(t2[2*root],t2[2*root+1]);
end;
function que1(root,l,r,x,y:longint):longint;
var mid:longint;
begin
  if (l=x)and(r=y) then exit(t1[root]);
  mid:=(l+r)div 2;
  if y<=mid then exit(que1(2*root,l,mid,x,y));
  if x>mid then exit(que1(2*root+1,mid+1,r,x,y));
  exit(max(que1(2*root,l,mid,x,mid),que1(2*root+1,mid+1,r,mid+1,y)));
end;
function que2(root,l,r,x,y:longint):longint;
var mid:longint;
begin
  if (l=x)and(r=y) then exit(t2[root]);
  mid:=(l+r)div 2;
  if y<=mid then exit(que2(2*root,l,mid,x,y));
  if x>mid then exit(que2(2*root+1,mid+1,r,x,y));
  exit(max(que2(2*root,l,mid,x,mid),que2(2*root+1,mid+1,r,mid+1,y)));
end;
procedure change(root,l,r,x,v1,v2:longint);
var mid:longint;
begin
  if l=r then begin
    t1[root]:=max(t1[root],v1);
    t2[root]:=max(t2[root],v2);
    exit;
  end;
  mid:=(l+r)div 2;
  if x<=mid then begin
    change(root*2,l,mid,x,v1,v2);
    t1[root]:=max(t1[root*2],t1[root*2+1]);
    t2[root]:=max(t2[root*2],t2[root*2+1]);
  end else begin
    change(root*2+1,mid+1,r,x,v1,v2);
    t1[root]:=max(t1[root*2],t1[root*2+1]);
    t2[root]:=max(t2[root*2],t2[root*2+1]);
  end;
end;
begin
  readln(n);
  for i:=1 to n do begin
    read(j);
    if j=1 then s[i]:=s[i-1]+1 else s[i]:=s[i-1]-1;
    if j=0 then inc(sum);
  end;
  inf:=-300000000;
  build(1,0,n);
  for i:=1 to n do f[i]:=inf;
  readln(q);
  for i:=1 to q do begin
    readln(l,r);
    ad(l,r);
  end;
  for i:=1 to n do begin
    j:=head[i];
    v:=que1(1,0,n,0,i-1);
    while j<>0 do begin
      f[t[j]]:=max(f[t[j]],v+s[t[j]]-s[i-1]);
      if i<t[j] then f[t[j]]:=max(f[t[j]],que2(1,0,n,i,t[j]-1)+s[t[j]]);
      j:=next[j];
    end;
    j:=head[i];
    while j<>0 do begin
      change(1,0,n,t[j],f[t[j]],f[t[j]]-s[t[j]]);
      j:=next[j];
    end;
  end;
  writeln(n-sum-que1(1,0,n,1,n));
end.

T2 留大坑,水过的!!!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值