jzoj5932. 【NOIP2018模拟10.27】情报中心
Description
题目背景
。飞纷火战来年近国 D 和国 C
。飞乱子鸽来年近国 D 和国 C
题面描述
最近,C 国成功地渗透进入了 D 国的一个城市。这个城市可以抽象成一张有 n 个节点,节点之间有 m 条双向道路连接的无向图,每条道路的⻓度都为 1 。
经过侦查,C 国情报部部⻓ GGB 惊讶地发现,这座看起来不起眼的城市竟然是 D 国的军事中心。因此 GGB 决定在这个城市内设立情报机构。情报专家 TAC 在侦查后,安排了 q 种设立情报机构的方案。这些方案中,第 i 种方案将计划建立 ki 个情报机构,第 j 个情报机构可以安排人员到距离其不超过 di,j 的节点上收集情报。
Input
从文件 center.in 中读入数据。
输入第一行包含三个正整数 n, m, q ,分别表示城市的节点个数、道路条数和方案个数。
接下去 m 行每行两个正整数 u, v ,表示存在一条连接城市 u 和城市 v 的双向道路。
接下去 q 行,每行表示一个方案。第一个正整数 k 表示该种方案将计划建立 k 个情报机构,之后是 2k 个正整数,其中第 2i − 1 个数表示方案中第 i 个情报机构所在的节点编号,第 2i 个数表示第 i 个情报点所能派出情报人员的最远距离。
Output
输出到文件 center.out 中。
输出包含 q 行,每行包含一个整数,表示相应询问的答案。
Sample Input
5 8 3
1 2
1 3
1 4
1 5
2 4
2 5
3 5
4 5
1 2 1
1 1 1
2 2 2 3 1
Sample Output
4
5
5
Data Constraint
题目更正:di,j值域在int范围内;q小于等于100000
题解
这题额,只有一个评价——语言歧视,不要脸。
首先,我们一个直观的想法——
f[i,j,k]表示第i个点,走了j步,能否到达k。
然而这样子空间不保证。
尝试把k看成一个状态。
那么就是:
f[i,j]表示第i个点,走了j步,能到达点的情况。
pascal就要多加维k,把1000压成32个longint存储2进制。
C++好像有一个叫做bitset的好家伙可以用。
然后我们每个点都做一遍bfs求得当前点到达每个点的最少步数。
这个是的。
然后处理出f数组。
这个是的。
然后,我们就每次把多个k给or起来,变成一个全新的数组,统计答案即可。
这个是的。
所以加起来时间过得去。
然鹅pascal做一遍就时间炸了。
我想静静。
标程
C++的:
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
int n,m,Q;
int ed[1000][1000];
int ne[10000];
struct Node{int x,s;} q[10000];
int vis[10000],nv;
bitset<1000> f[1000][1000],ans;
int maxdis[1000];
int main(){
freopen("center.in","r",stdin);
freopen("center.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
for (int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v),--u,--v;
ed[u][v]=1;
ed[v][u]=1;
}
for (int i=0;i<n;++i)
{
for (int j=0;j<n;++j)
{
if (ed[i][j])
{
ed[i][ne[i]++]=j;
}
}
}
for (int i=0;i<n;++i)
{
++nv;
vis[i]=nv;
f[i][0][i]=1;
int h=-1,t=0;
q[0]={i,0};
do
{
++h;
int u=q[h].x;
for (int j=0;j<ne[u];++j)
{
int to=ed[u][j];
if (vis[to]^nv)
{
q[++t]={to,q[h].s+1};
vis[to]=nv;
f[i][q[t].s][to]=1;
}
}
}
while (h^t);
maxdis[i]=q[t].s;
for (int j=1;j<=maxdis[i];++j)
{
f[i][j]|=f[i][j-1];
}
}
while (Q--)
{
int K;
scanf("%d",&K);
ans.reset();
while (K--)
{
int x,len;
scanf("%d%d",&x,&len),--x;
len=min(maxdis[x],len);
ans|=f[x][len];
}
printf("%d\n",ans.count());
}
return 0;
}
pascal的:
{$inline on}
uses math;
const up=1000;
type
new=record
x,step:longint;
end;
var
i,j,k,l,n,m,q,tot,ans,head,tail,took,x,y,st,long,start:longint;
p:int64;
a:array[1..2000*up] of new;
bz:array[1..up] of boolean;
cd:array[1..up] of longint;
tov,next,last:array[1..200000] of longint;
f:array[1..up,0..up,0..20] of int64;
em:array[0..20] of int64;
mi:array[0..63] of int64;
map:array[1..up,1..up] of boolean;
procedure bfs(dep:longint);inline;
var
i,j,k,l,st,step:longint;
begin
st:=a[dep].x;
step:=a[dep].step;
for i:=1 to n do
begin
if map[st,i] then
begin
if bz[i] then
begin
inc(took);
a[took].x:=i;
a[took].step:=step+1;
cd[i]:=step+1;
bz[i]:=false;
j:=i;
k:=1;
while j>=63 do
begin
j:=j-63;
k:=k+1;
end;
inc(f[start,step+1,k],mi[j]);
end;
end;
end;
end;
begin
assign(input,'center.in');reset(input);
assign(output,'center.out');rewrite(output);
readln(n,m,q);
for i:=1 to m do
begin
readln(x,y);
map[x,y]:=true;
map[y,x]:=true;
end;
mi[0]:=1;
for i:=1 to 62 do
begin
mi[i]:=mi[i-1]*2;
end;
for i:=1 to n do
begin
head:=1;
tail:=1;
took:=1;
a[1].x:=i;
a[1].step:=0;
fillchar(bz,sizeof(bz),true);
fillchar(cd,sizeof(cd),0);
bz[i]:=false;
start:=i;
k:=1;
j:=i;
while j>=63 do
begin
j:=j-63;
inc(k);
end;
f[i,0,k]:=mi[j];
repeat
for j:=head to tail do
begin
bfs(j);
end;
head:=tail+1;
tail:=took;
until head>tail;
for j:=1 to n do
begin
for k:=1 to 20 do
begin
f[i,j,k]:=f[i,j,k] or f[i,j-1,k];
end;
end;
end;
for i:=1 to q do
begin
read(k);
fillchar(em,sizeof(em),0);
for j:=1 to k do
begin
read(st,long);
for l:=1 to 16 do
begin
em[l]:=em[l] or f[st,long,l];
end;
end;
ans:=0;
for l:=1 to 16 do
begin
p:=em[l];
while p>0 do
begin
if p mod 2=1 then inc(ans);
p:=p div 2;
end;
end;
writeln(ans);
end;
end.