C - Spiral Rotation
赛时未做出,并浪费了大量时间一错再错。
关键词:变换周期
启发:
图+位置变换一定要动手画图,并模拟一下,不难发现会有周期。
E - 3 Team Division
要点:1.注意关注数据范围 2.学会经典时间优化技巧
2中提及到的经典技巧:知道n个元素的结合S,那么可以通过枚举n-1个元素,用S减少n-1的集合,求的最后一个元素。
F - Road Blocked
注意到:N <= 300
顺序操作是减边
逆转操作就是加边
更新减边的最短路或许很难,但是更新加边的最短路或许简单。
设置 $dp_{k,x,y}$ 表示只考虑前 $k$ 条边 从 $x->y$ 的最短距离,那么转移情况就是是否使用第k条边,时间为 $O(1)$。
对于新加1条边,更新全部状态的时间就是 $O(N * N)$
假设加T条边,时间就是 O(K * N * N)
对于未删除的边可以Floyd $O(N^3)$ 预处理
逆序操作中途中不断记录答案即可,记得逆转输出
const int N = 300 + 10, M = N * N;
struct Edge{
ll u, v, w;
}e[M];
int n, m, q;
int ty[M]; //道路是否被删除
ll f[N][N];
void solve(){
cin >> n >> m >> q;
for (int i = 1; i <= m; i ++ ){
int u, v, w;
cin >> u >> v >> w;
e[i] = {u, v, w};
}
vector<tuple<int, int, int>> vq;
for (int i = 1; i <= q; i ++ ){
int c;
cin >> c;
if (c == 1){
int cx;
cin >> cx;
ty[cx] = 1;//删除
vq.push_back(make_tuple(c, cx, 0));
}else{
int u, v;
cin >> u >> v;
vq.push_back(make_tuple(c, u, v));
}
}
//floyd -初始化
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
f[i][j] = i == j ? 0 : 1e18;
for (int i = 1; i <= m; i ++ )
if (ty[i] == 0){
auto [u, v, w] = e[i];
f[u][v] = min(f[u][v], w);
f[v][u] = min(f[v][u], w);
}
//预处理最短路
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
//处理询问
reverse(vq.begin(), vq.end());
vector<ll> ans;
for (int i = 0; i < vq.size(); i ++ )
if (get<0>(vq[i]) == 1){ //加边
int id = get<1>(vq[i]);
auto [u, v, w] = e[id];
for (int x = 1; x <= n; x ++ )
for (int y = 1; y <= n; y ++ ){
f[x][y] = min(f[x][y], f[x][u] + f[v][y] + w);
f[x][y] = min(f[x][y], f[x][v] + f[u][y] + w);
}
}else{ //询问
auto [c, x, y] = vq[i];
if (f[x][y] < 1e18)
ans.push_back(f[x][y]);
else
ans.push_back(-1);
}
reverse(ans.begin(), ans.end());
for (auto d : ans){
cout << d << '\n';
}
}