曾经做过的一些小水题, 总之我是不会做.
这是第2篇.
TCO 2014 Wildcard Round
解题口胡报告.
275
假如有两个$[0,2^n-1]$的排列 $p$ 和 $q$ , 还有一个01矩阵. 矩阵的格子$(i,j)$的值取决于$p_i\,\,AND\,\,q_j$ 是否非0.
现在给你一个矩阵, 问是否存在一种方案能构造这幅画.
orz jcvb.
首先找到每个2的幂次在哪一行(当然列也可以). 特征是这一行有$2^{n-1}$个1.
然后我们就可以对于二的幂次根据每一列在这些行的01状态计算出每一列的值了. 这期间发现不合法就判掉了.
然后再计算出每一行的值, 判掉不合法情况.
AndPicture.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include <bits/stdc++.h>
using namespace std;
int bit[10], ptr; int mp[100], use[100], mtr[100][100]; int col[100], mp2[100], row[100];
class AndPicture { public: inline int checkLine(vector<string>::iterator Line) { int Count = 0; for (string::iterator ch = Line->begin(); ch != Line->end(); ++ch) { if ((*ch) == '1') Count++; } return Count; } string isPossible(int n, vector<string> picture) { int idx = 0; for (vector<string>::iterator Line = picture.begin(); Line != picture.end(); ++Line) { idx++; if (checkLine(Line) == (1 << (n - 1))) { bit[ptr] = 1; mp[idx] = (1 << ptr); ptr++; } for (int i = 0; i < (1 << n); ++i) { mtr[idx][i + 1] = (Line->at(i) == '1'); } } if (ptr != n) return string("Impossible"); for (int j = 1; j <= (1 << n); ++j) { int bitcount = 0; for (int i = 1; i <= (1 << n); ++i) { if (mp[i] && mtr[i][j]) col[j] |= mp[i], bitcount++; } if (use[col[j]]) return string("Impossible"); else use[col[j]] = 1; if (bitcount == 1) mp2[j] = col[j]; } memset(use, 0, sizeof use); for (int i = 1; i <= (1 << n); ++i) { if (mp[i]) { if (use[mp[i]]) return string("Impossible"); else use[mp[i]] = 1; continue; } for (int j = 1; j <= (1 << n); ++j) { if (mp2[j] && mtr[i][j]) row[i] |= mp2[j]; } if (use[row[i]]) return string("Impossible"); else use[row[i]] = 1; } for (int i = 1; i <= (1 << n); ++i) for (int j = 1; j <= (1 << n); ++j) { if (bool(row[i] & col[j]) != bool(mtr[i][j])) return string("Impossible"); } return string("Possible"); } };
|
750
一个$n \times m$矩阵的每个格子, 可以选$[1,c]$的一个整数, 求有多少种方案使得任意两行之间, 任意两列之间都不相同. $n \le 5000$.
先不考虑列. 只让每行都不同, 有$n! {c^{m} \choose n}$种方案. 这样列上就有至多$m$种, 至少1种等价类. 下面考虑把等价类限制在$m$.
如果我们记至多$i$类为$f_i$, 恰好为$g_i$, 那么我们有$f_i = \sum_{j=1}^{i}{S(i,j)g_j}$, $S$是第二类斯特林数, 对应把$i$个物品分为$j$个集合的方案数.
因为$S(i,i)=1$, 移项得$g_i = f_i - \sum_{j = 1}^{i - 1}S(i,j)g_j$. 这可以$O(n^2)$做的. $f$就是下降幂.
CountTables.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <bits/stdc++.h>
using namespace std; typedef long long ll;
const ll mod = 1e+9 + 7; const int maxn = 5005;
ll s[maxn][maxn], f[maxn], g[maxn];
class CountTables { public: void init() { s[1][1] = 1; for (int i = 2; i <= 4000; ++i) { s[i][1] = s[i][i] = 1; for (int j = 2; j < i; ++j) s[i][j] = (s[i - 1][j - 1] + 1ll * s[i - 1][j] * j % mod) % mod; } } inline ll quick_power(ll base, ll index) { ll ret = 1; while (index) { if (index & 1) ret = ret * base % mod; base = base * base % mod; index >>= 1; } return ret; } int howMany(int N, int M, int C) { init(); for (int i = 1; i <= M; ++i) { ll bgn = quick_power(C, i), minus = 0; ll ret = bgn; for (int j = 2; j <= N; ++j) { minus--; ret = (ret * ((bgn + minus + mod) % mod)) % mod; } f[i] = ret; } for (int i = 1; i <= M; ++i) { g[i] = f[i]; for (int j = 1; j < i; ++j) { g[i] = (g[i] - s[i][j] * g[j] % mod + mod) % mod; } } return g[M]; } };
|
1100
一个矩阵, 有些地方是坏点. 给你开始坐标和目的坐标, 一开始有$E$点能量. 每次你可以选择原地不动耗费一点能量, 或者向四个方向跳当前能量的距离.
问能否到达目的坐标.
不想写了把每个点拆成四个点, 可以向四个方向转移. 然后按能量做分层BFS, 求到达每个点的剩余最大能量.