传送门
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; }