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求得当前点到达每个点的最少步数。
这个是 O ( n ∗ m ) O(n*m) O(nm)的。
然后处理出f数组。
这个是 O ( n 3 / 32 ) O(n^3/32) O(n3/32)的。
然后,我们就每次把多个k给or起来,变成一个全新的数组,统计答案即可。
这个是 O ( ( ∑ k ) ∗ 32 ) O((\sum{k})*32) O((k)32)的。
所以加起来时间过得去。
然鹅pascal做一遍 O ( n ∗ m ) O(n*m) O(nm)就时间炸了。
我想静静。

标程

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.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值