2017-09-23校训练题题解

来源:互联网 发布:sql注入是什么 编辑:程序博客网 时间:2024/05/19 19:13

t1

题解

定义f[i][j]表示i次操作后x的数值为j的概率。DP转移可以转化为矩阵乘法形式,利用矩阵快速幂进行优化。但是我们发现转移还是矩阵的形式,而且是循环矩阵的形式。循环矩阵快速幂

#include<set>#include<queue>#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include<algorithm>using namespace std;inline int read() {int x = 0, flag = 1; char ch = getchar();while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }return x * flag;}#define rep(ii, aa, bb) for (int ii = aa; ii <=  bb; ii++)#define drp(ii, aa, bb) for (int ii = aa; ii >= bb; ii--)#define ha 1000000007#define ll long long#define MOD 1001int n, m, mod, a;ll ans[MOD][2], t[MOD][2] = {};int ansPos = 0, tmpPos = 0;int mult(ll x) {ll ret = 1;int k = ha - 2;while(k) {if (k & 1) ret = ret * x % ha;x = x * x % ha;k >>= 1;}return ret;}void matrixMult() {while (m) {if (m & 1) {ansPos ^= 1;rep(i, 1, mod - 1) ans[i][ansPos] = 0;rep(i, 1, mod - 1) rep(j, 1, mod - 1)ans[i * j % mod][ansPos] += ans[i][ansPos ^ 1] * t[j][tmpPos] % ha;rep(i, 1, mod - 1) ans[i][ansPos] %= ha;}tmpPos ^= 1;rep(i, 1, mod - 1) t[i][tmpPos] = 0;rep(i, 1, mod - 1) rep(j, 1, mod - 1)t[i * j % mod][tmpPos] += t[i][tmpPos ^ 1] * t[j][tmpPos ^ 1] % ha;rep(i, 1, mod - 1) t[i][tmpPos] %= ha;m >>= 1;}}int main() {n = read(), m = read(), mod = read();rep(i, 1, n) t[read()][tmpPos]++;int rn = mult(n);rep(i, 1, mod - 1) t[i][tmpPos] = t[i][tmpPos] * rn % ha;ans[1][ansPos] = 1;matrixMult();ll ansTot = 0;rep(i, 1, mod - 1) ansTot = (ansTot + ans[i][ansPos] * i) % ha;printf("%lld\n", ansTot);return 0;}


t2

对于任意一列,两行之间的差相等”是一个很重要的性质.这告诉我们:每一列差分后得到的结果相同.每一行差分后的结果也相同.于是我们对行列分别用带权并查集维护行之间,列之间的差分关系.如果差分关系出现矛盾(两行之间的差值可以推导出两种可能)则无解.如果差分关系没有矛盾,则需要求出整个矩阵中能推导出的最小值判断是否小于0.这里的推导方法是:维护差分关系的并查集必然分成了多个连通块.一种直观的方法是,枚举一个关于行的连通块,再枚举一个关于列的连通块,这两个连通块相交产生的格子中的最小值位于列和行的最小值的交点.这样的时间复杂度是很高的.实际上我们只需考虑每个关于列的连通块.对于一个关于列的连通块,我们求出这个连通块中数值最小的一列.考虑这个连通块中所有的已知数字,每个已知数字都可以求出数值最小的一列中某一个数值.在这些数值中取最小值即可,实现的时候,只需用每个已知数字求出这个连通块中某一列的最小值,再从这一列的最小值转换到最小的一列的最小值.

#include<set>#include<queue>#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include<algorithm>using namespace std;inline int read() {int x = 0, flag = 1; char ch = getchar();while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }return x * flag;}#define rep(ii, aa, bb) for (int ii = aa; ii <=  bb; ii++)#define ll long long#define N 200001struct point {int r, c, w;}pp[N];int R, C, n;int fa[N];int w[N], st[N], mi[N];bool cmpr(const point &a, const point &b) { return a.c < b.c; }int find(int x) {if (fa[x] == x)return x;int rt = find(fa[x]);w[x] += w[fa[x]];return fa[x] = rt;}bool merge(int a, int b, int c) {int ra = find(a), rb = find(b);if (ra != rb) {fa[ra] = rb;w[ra] = c - w[a] + w[b];return true;}else return w[a] == w[b] + c;}bool judge() {rep(i, 0, n) if (pp[i].w < 0) return 0;rep(i, 0, n) fa[i] = i, w[i] = 0;sort(pp + 1, pp + 1 + n, cmpr);rep(i, 1, n - 1) if(pp[i].c == pp[i + 1].c)if(!merge(pp[i].r, pp[i + 1].r, pp[i + 1].w - pp[i].w))return false;memset(st, 0x3f, sizeof(st));memset(mi, 0x3f, sizeof(mi));rep(i, 1, n) {int rt = find(pp[i].r);st[rt] = min(st[rt], pp[i].w + w[pp[i].r]);}rep(i, 0, R) {int rt = find(i);mi[rt] = min(mi[rt], -w[i]);}rep(i, 0, R) if (fa[i] == i && st[i] + mi[i] < 0) return false;return true;}int main() {int T = read();while (T--) {R = read(), C = read(), n = read();rep(i, 1, n) pp[i].r = read(), pp[i].c = read(), pp[i].w = read();printf("%s\n", judge() ? "Yes" : "No");}return 0;}

t3

题面太暴力,题太水(虽然我没写),不挂了