HUPC2021
各行・列はある友人が送った手紙が別の友人に届くまでの日数の最大値で拡張します(制約から、行数・列数は1100以下になります)。
行列全体が
この行列累乗を適切に実装すると、
各要素がbool値で加法がBitwise OR、乗法がBitwise ANDであることに注目すると、行・列ごとにbitsetでまとめて計算することで高速化することができます。
bitsetの配列で行列を計算することで、行列の積が
行列累乗全体の計算量は
以下実装例
#include <bits/stdc++.h>
using namespace std;
const size_t MAT_ORDER = 1100;
struct BitsetSquareMatrix {
using BSMatrix = BitsetSquareMatrix;
using matrix = array<bitset<MAT_ORDER>, MAT_ORDER>;
matrix rmat, cmat;
BitsetSquareMatrix(){}
inline void set(int r, int c) {
rmat[r].set(c);
cmat[c].set(r);
}
inline bool get(int r, int c) {
return rmat[r][c];
}
inline BSMatrix &operator*=(const BSMatrix &A) {
matrix rres, cres;
for (int i = 0; i < MAT_ORDER; i++){
for (int j = 0; j < MAT_ORDER; j++){
rres[i][j] = (rmat[i] & A.cmat[j]).any();
cres[j][i] = rres[i][j];
}
}
rmat.swap(rres);
cmat.swap(cres);
return (*this);
}
inline BSMatrix &operator^=(long long p) {
BSMatrix res = BSMatrix();
for (int i = 0; i < MAT_ORDER; i++){
res.rmat[i].set(i);
res.cmat[i].set(i);
}
while(p > 0){
if (p & 1) res *= *this;
*this *= *this;
p >>= 1;
}
rmat.swap(res.rmat);
cmat.swap(res.cmat);
return (*this);
}
BSMatrix operator*(const BSMatrix &B) const { return (BSMatrix(*this) *= B); }
BSMatrix operator^(const long long k) const { return (BSMatrix(*this) ^= k); }
friend ostream &operator<<(ostream &os, BSMatrix &p) {
for (int i = 0; i < MAT_ORDER; i++) {
os << "[";
auto str = p.rmat[i].to_string();
reverse(str.begin(), str.end());
os << str;
os << "]\n";
}
return (os);
}
};
int main() {
int N, D;
cin >> N >> D;
vector maxD(N, 1);
vector<vector<int>> v(N), d(N);
for (int i = 0; i < N; i++) {
int K;
cin >> K;
v[i].resize(K), d[i].resize(K);
for (int j = 0; j < K; j++) {
cin >> v[i][j] >> d[i][j];
v[i][j]--;
maxD[i] = max(maxD[i], d[i][j]);
}
}
vector dacc(N + 1, 0);
for (int i = 0; i < N; i++)
dacc[i + 1] = dacc[i] + maxD[i];
// idxのday日後に対応する行列Aのインデックスを求める
auto get_id = [&](int idx, int day) -> int {
assert(dacc[idx] + day >= 0);
return dacc[idx] + day;
};
BitsetSquareMatrix A;
for (int i = 0; i < N; i++) {
for (int j = 0; j < v[i].size(); j++) {
A.set(get_id(i, d[i][j] - 1), get_id(v[i][j], 0));
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < maxD[i] - 1; j++){
A.set(get_id(i, j), get_id(i, j + 1));
}
}
A ^= D;
vector<int> ans;
for (int i = 0; i < N; i++) {
bool isok = true;
for (int j = 0; j < N; j++) {
if (!A.get(get_id(j, 0), get_id(i, 0))) isok = false;
}
if (isok) ans.emplace_back(i);
}
cout << ans.size() << endl;
for (auto a : ans) cout << a + 1 << " ";
cout << endl;
}
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up