1. 程式人生 > >JZOJ5932. 【NOIP2018模擬10.27】情報中心

JZOJ5932. 【NOIP2018模擬10.27】情報中心

傳送門

preface

  這道題資料超級水,暴力70。正解也超級玄學,需要各種卡常技巧。

分析

  首先看資料範圍,貌似O(k)才能過廢話。既然是要O(k)的出答案,那就只能預處理了。

  設f[i][j][k]表示以第i好結點為起點,在最短距離不超過j的情況下,是否能到達k號結點。對於這樣的東西,我們可以做一個多源最短路。之後再把f[i][j][k]和f[i][j-1][k]或一下就可以了。

  但是n3的空間顯然是掛的,那麼考慮用bitset來優化。f[i][j]還是表示一樣的東西,00100101...這樣的序列就表示能否到達咯。

  最後再卡卡常數什麼的就OK了。

code

#pragma
GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define ll long long #define maxn 1010 #define reg register using namespace std; inline void read(int &x) { x=0; reg char s=getchar(); while(s<'0'||s>'9') s=getchar(); while(s>='0'&&s<='9') x=x*10
+s-'0',s=getchar(); } inline void print(int x) { if(x>9) print(x/10); putchar(x%10+'0'); } int n,m,pro,dis[maxn]; vector<int> edge[maxn]; bool vis[maxn]; bitset<maxn> f[maxn][maxn]; void bfs(int s) { memset(dis,-1,sizeof dis); memset(vis,false,sizeof vis); queue<int> q; q.push(s); dis[s]
=0,vis[s]=true; while(!q.empty()) { reg int u=q.front(); q.pop(); for(reg int i=0,sz=edge[u].size(); i<sz; i++) { reg int v=edge[u][i]; if(!vis[v]) { vis[v]=true; dis[v]=dis[u]+1; q.push(v); } } } for(reg int i=1; i<=n; i++) if(dis[i]!=-1) f[s][dis[i]].set(i); } int main() { read(n),read(m),read(pro); reg int x,y,z; for(reg int i=1; i<=m; i++) { read(x),read(y); edge[x].push_back(y); edge[y].push_back(x); } for(reg int i=1; i<=n; i++) bfs(i); for(reg int i=1; i<=n; i++)//起點 for(reg int j=1; j<=n; j++)//距離 f[i][j]|=f[i][j-1]; for(reg int i=1; i<=pro; i++) { read(x); bitset<maxn> tmp; for(reg int j=1; j<=x; j++) { read(y),read(z); z=min(z,n); tmp|=f[y][z]; } print(tmp.count()),putchar('\n');//用count直接數出1的個數會快很多 } return 0; }