20161104测试总结

T1

此题说好的linux评测,然后在windows评测机上就2333了…

注意读入,注意windows上的读入

一看这题不就是矩阵乘法,$O(n^3)$ T掉,应该先预处理 $sum A_j = \sum limits_{i = 0}^{N - 1} A_{i,j}$ 和 $sum B_j = \sum\limits_{k = 0}^{N - 1} B_{j,k}$ ,那么 $sum = \sum_\limits{i=0}^{N-1}\sum\limits_{j=0}^{N-1}A_{i,j}sumB_j = \sum\limits_{j=0}^{N-1}\sum\limits_{k=0}^{N-1}B_{j,k}sumA_j$。

因此,我们只需要$O(n^2)$计算出一开始的 $sum$ 值,每次修改$O(1)$更新$sumA,sumB,sum$。

时间复杂度为$O(n^2+q)$。

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
62
63
#include <bits/stdc++.h>
using namespace std;
const int iol = 1024 * 1024;
char buf[iol], *ioh, *iot, ioc;
bool iosig;
inline char read() {
if(ioh == iot) {
iot = (ioh = buf) + fread(buf, 1, iol, stdin);
if(ioh == iot) return -1;
}
return *ioh++;
}
template<class T>
inline void read(T& x) {
iosig = false;
for(ioc = read(); !isdigit(ioc); ioc = read()) {
if(ioc == '-') iosig = true;
}
x = 0;
while(ioc == '0') ioc = read();
for(; isdigit(ioc); ioc = read())
x = (x << 1) + (x << 3) + (ioc ^ '0');
if(iosig) x = -x;
}
const int MAXN = 1010;
struct Matrix {
long long val[MAXN][MAXN];
long long sumx[MAXN], sumy[MAXN];
} a, b;
int n;
long long ans;
int main() {
read(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
read(a.val[i][j]);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
read(b.val[i][j]);
for (int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
a.sumx[i] += a.val[i][j], b.sumx[i] += b.val[i][j];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a.sumy[i] += a.val[j][i], b.sumy[i] += b.val[j][i];
for (int i = 0; i < n; i++)
ans += a.sumy[i] * b.sumx[i];
int q;
read(q);
for (int i = 0, x, y, k; i < q; i++) {
ioc = read();
while (ioc == '\n' || ioc == '\r' || ioc == ' ') ioc = read();
if (ioc == 'A') {
read(x), read(y), read(k);
a.sumx[x] -= a.val[x][y], a.sumx[x] += k, a.sumy[y] -= a.val[x][y], a.sumy[y] += k, ans -= a.val[x][y] * b.sumx[y], ans += k * b.sumx[y], a.val[x][y] = k;
} else {
read(x), read(y), read(k);
b.sumx[x] -= b.val[x][y], b.sumx[x] += k, b.sumy[y] -= b.val[x][y], b.sumy[y] += k, ans -= b.val[x][y] * a.sumy[x], ans += k * a.sumy[x], b.val[x][y] = k;
}
cout << ans << "\n";
}
return 0;
}

T2-最小生成树

没想到正解,作死写高精度+dijkstra,60分…
由于所有边权均为$2^i$的形式,且没有两条边的权值相同,所以要优先最小化经过的最大边。
我们只需要求出最小生成树,统计所有边对答案的贡献(即这条边两端联通块大小的乘积)。
时间复杂度$O(E log V)$。

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <bits/stdc++.h>
using namespace std;
const int iol = 1024 * 1024;
char buf[iol], *ioh, *iot, ioc;
bool iosig;
inline char read() {
if(ioh == iot) {
iot = (ioh = buf) + fread(buf, 1, iol, stdin);
if(ioh == iot) return -1;
}
return *ioh++;
}
template<class T>
inline void read(T& x) {
iosig = false;
for(ioc = read(); !isdigit(ioc); ioc = read()) {
if(ioc == '-') iosig = true;
}
x = 0;
while(ioc == '0') ioc = read();
for(; isdigit(ioc); ioc = read())
x = (x << 1) + (x << 3) + (ioc ^ '0');
ioh--;
if(iosig) x = -x;
}
const int maxn = 100010;
int n;
struct Node {
int u, v, w;
Node() {}
Node(int _v, int _w): u(-1), v(_v), w(_w) {}
Node(int _u, int _v, int _w): u(_u), v(_v), w(_w) {}
inline bool operator < (const Node&_n) const {
return w > _n.w;
}
};
typedef priority_queue<Node> heap;
vector<Node> edge[maxn], mst[maxn];
bool vis[maxn];
unsigned int twobuf[maxn * 100];
inline void addEdge(int u, int v, int w, vector<Node>*vc) {
vc[u].push_back(Node(u, v, w));
vc[v].push_back(Node(v, u, w));
}
inline void prim(int s = 1) {
heap q;
Node t;
q.push(Node(s, 0));
while (!q.empty()) {
t = q.top(); q.pop();
if (vis[t.v]) continue;
if (t.u != -1) addEdge(t.u, t.v, t.w, mst);
vis[t.v] = true;
for (register int i = 0; i < edge[t.v].size(); i++)
if (!vis[edge[t.v][i].v])
q.push(Node(edge[t.v][i].u, edge[t.v][i].v, edge[t.v][i].w));
}
}
int m;
int size[maxn];
inline void dfs(int u = 1, int pre = 1) {
size[u] = 1;
for (int i = 0; i < mst[u].size(); i++) {
Node *x = &mst[u][i];
if (x->v == pre) continue;
dfs(x->v, u);
size[u] += size[x->v];
twobuf[x->w + 1] = (unsigned int)size[x->v] * (n - size[x->v]);
}
}
int main() {
read(n), read(m);
for (register int i = 0, u, v, w; i < m; i++)
read(u), read(v), read(w), addEdge(u, v, w, edge);
prim();
dfs();
for(int i = 1; i <= m; i++)
twobuf[i + 1] += twobuf[i] >> 1, twobuf[i] %= 2;
unsigned int x = twobuf[m+1];
register int top = m + 1;
while(x) top++, twobuf[top] = x >> 1, twobuf[top - 1] = x % 2, x = twobuf[top];
while(!twobuf[top]) top--;
reverse(twobuf + 1, twobuf + top + 1);
for (int i = 1; i <= top; i++)
cout << twobuf[i];
return 0;
}

T3-Hash

Hash大法好啊…
此题正解Hash,首先枚举一个起点,为了对字符串进行计数,考虑将路径上得到的字符串进行Hash,每次只需要对三个串的Hash值进行拼接,并通过翻转字符串实现计算四种情况。
时间复杂度为$O(n^2)$。
注意使用双Hash

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
62
63
64
65
66
#include <bits/stdc++.h>
const int h1 = 31;
const int h2 = 233;
const int p = 1000000007;
const int H = 2333333;
using namespace std;
typedef unsigned long long HashType;
HashType hash1[5][605], hash2[5][605], pow1[10005], pow2[10005], now1, now2;
int son[H + 5], nxt[5000005], tot;
HashType num1[5000005], num2[5000005];
char s[5][605];
inline void add(HashType x1, HashType x2) {
int i, y = x1 % H;
for (i = son[y]; i; i = nxt[i])
if (num1[i] == x1 && num2[i] == x2)
return;
num1[++tot] = x1;
num2[tot] = x2;
nxt[tot] = son[y];
son[y] = tot;
}
int main() {
setvbuf(stdin, new char[1 << 20], _IOFBF, 1 << 20);
int t, n, i, j, k;
for (pow1[0] = pow2[0] = i = 1; i <= 1500; ++i) pow1[i] = pow1[i - 1] * h1, pow2[i] = (pow2[i - 1] * h2) % p;
fscanf(stdin, "%d", &n);
fscanf(stdin, "%s", s[1] + 1);
fscanf(stdin, "%s", s[2] + 1);
tot = 0;
for (t = 1; t <= 4; t++) {
for (i = 1; i <= n; i++) {
hash1[1][i] = hash1[2][i] = hash2[1][i] = hash2[2][i] = 0;
for (j = i; j > 0; j--) hash1[1][i] = hash1[1][i] * h1 + s[1][j];
for (j = 1; j <= i; j++) hash1[1][i] = hash1[1][i] * h1 + s[2][j];
for (j = i; j > 0; j--) hash1[2][i] = hash1[2][i] * h1 + s[2][j];
for (j = 1; j <= i; j++) hash1[2][i] = hash1[2][i] * h1 + s[1][j];
for (j = i; j > 0; j--) hash2[1][i] = (hash2[1][i] * h2 + s[1][j]) % p;
for (j = 1; j <= i; j++) hash2[1][i] = (hash2[1][i] * h2 + s[2][j]) % p;
for (j = i; j > 0; j--) hash2[2][i] = (hash2[2][i] * h2 + s[2][j]) % p;
for (j = 1; j <= i; j++) hash2[2][i] = (hash2[2][i] * h2 + s[1][j]) % p;
}
for (i = 1; i <= n; i++) {
now1 = now2 = 0;
for (j = i; j <= n; j++) now1 = now1 * h1 + s[1][j];
for (j = n; j >= i; j--) now1 = now1 * h1 + s[2][j];
for (j = i; j <= n; j++) now2 = (now2 * h2 + s[1][j]) % p;
for (j = n; j >= i; j--) now2 = (now2 * h2 + s[2][j]) % p;
k = 2;
for (j = i; j >= 1; j--) {
add(now1 * pow1[(j << 1) - 2] + hash1[k][j - 1], (now2 * pow2[(j << 1) - 2] + hash2[k][j - 1]) % p);
now1 = now1 * h1 + s[k][j - 1];
now2 = (now2 * h2 + s[k][j - 1]) % p;
k = 3 - k;
now1 = now1 * h1 + s[k][j - 1];
now2 = (now2 * h2 + s[k][j - 1]) % p;
}
}
for (i = 1; i <= n; i++) swap(s[1][i], s[2][i]);
if (t == 2) {
reverse(s[1] + 1, s[1] + n + 1);
reverse(s[2] + 1, s[2] + n + 1);
}
}
cout << tot;
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×