http://uoj.ac/problem/111
好像NOIP里面的题目...有好多都是...能通过xjbg剪枝来...AC题目的?
得好好学一下这些剪枝黑科技了...
思路:我觉得这位大佬说的很完善了:http://blog.csdn.net/herano/article/details/58639052
竟然能卡分块暴力...hack数据不良心...不过好像最坏情况的边实在是太多了,没办法改变MLE的结局...?(其实3000000还好吧?)
然后就是xjbg优化了,对每一个块删除重复跑的。对于step<=sqrt(n)的,我们如果找到了下一个块中存在step相同的,我们就不用再找了,好像就是这样= =。
然后spfa跑一波即可(竟然卡了dijstra,难道要手写堆吗?)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #pragma comment(linker,"/STACK:102400000,102400000") #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 30000 + 5; int n, m; int d[maxn]; vector<int> G[maxn]; bool have[maxn][200 + 5]; int s, t; bool vis[maxn]; int solve(){ queue<int> que; memset(d, 0x7f, sizeof(d)); d[s] = 0; que.push(s); while (!que.empty()){ int u = que.front(); que.pop(); vis[u] = false; for (int i = 0; i < G[u].size(); i++){ int step = G[u][i]; for (int j = 1; u + step * j < n; j++){ int v = u + step * j; if (d[v] > d[u] + j){ d[v] = d[u] + j; if (!vis[v]){ que.push(v); vis[v] = true; } } if (step <= 200 && have[v][step]) break; } for (int j = 1; u - step * j >= 0; j++){ int v = u - step * j; if (d[v] > d[u] + j){ d[v] = d[u] + j; if (!vis[v]){ que.push(v); vis[v] = true; } } if (step <= 200 && have[v][step]) break; } } } return d[t] == 0x7f7f7f7f ? -1 : d[t]; } int main(){ cin >> n >> m; for (int i = 0; i < m; i++){ int a, b; scanf("%d%d", &a, &b); if (i == 0) s = a; if (i == 1) t = a; G[a].pb(b); if (b <= 200) have[a][b] = 1; } for (int i = 0; i < n; i++){ sort(ALL(G[i])); G[i].erase(unique(ALL(G[i])), G[i].end()); } printf("%d ", solve()); return 0; }