Bronze

B1

import sys
sys.stdin = open('herding.in', 'r')
sys.stdout = open('herding.out', 'w')
x, y, z = sorted(map(int, raw_input().split()))
z -= y + 1
y -= x + 1
if y == 0 and z == 0:
    print 0
elif y == 1 or z == 1:
    print 1
else:
    print 2
print max(y, z)

B2

import sys
sys.stdin = open('revegetate.in', 'r')
sys.stdout = open('revegetate.out', 'w')
n, m = map(int, raw_input().split())
a = [[] for i in range(n + 1)]
for i in range(m):
    x, y = map(int, raw_input().split())
    a[x].append(y)
    a[y].append(x)
c = [0 for i in range(n + 1)]
s = ''
for i in range(1, n + 1):
    t = set(range(1, 5))
    for j in a[i]:
        if j < i and c[j] in t:
            t.remove(c[j])
    c[i] = list(t)[0]
    s += str(c[i])
print s

B3

import sys
sys.stdin = open('traffic.in', 'r')
sys.stdout = open('traffic.out', 'w')
n = input()
a = []
for i in range(n):
    x, y, z = raw_input().split()
    y = int(y)
    z = int(z)
    a.append((x, y, z))

l, h = 0, 1000000
for x, y, z in a[::-1]:
    if x == 'none':
        l = max(l, y)
        h = min(h, z)
    elif x == 'on':
        l -= z
        h -= y
    elif x == 'off':
        l += y
        h += z
l = max(l, 0)
print l, h
l, h = 0, 1000000
for x, y, z in a:
    if x == 'none':
        l = max(l, y)
        h = min(h, z)
    elif x == 'on':
        l += y
        h += z
    elif x == 'off':
        l -= z
        h -= y
l = max(l, 0)
print l, h

Silver

S1

#include <bits/stdc++.h>
using namespace std;
int n, a[100020];
int work() {
    if (a[n - 1] == a[0] + n - 1) {
        return 0;
    }
    if (a[n - 2] == a[0] + n - 2 || a[n - 1] == a[1] + n - 2) {
        if (a[n - 1] == a[0] + n) {
            return 1;
        } else {
            return 2;
        }
    }
    int z1 = n;
    for (int i = 0; i < n; i++) {
        int p = a[i] + n - 1;
        int t = upper_bound(a, a + n, p) - a;
        z1 = min(z1, n - (t - i));
    }
    for (int i = 0; i < n; i++) {
        int p = a[i] - n + 1;
        int t = lower_bound(a, a + n, p) - a - 1;
        z1 = min(z1, n - (i - t));
    }
    return z1;
}
int main() {
    freopen("herding.in", "r", stdin);
    freopen("herding.out", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(a, a + n);
    int z2 = max(a[n - 1] - a[1], a[n - 2] - a[0]) - n + 2;
    cout << work() << endl;
    cout << z2 << endl;
}

S2

#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[1020][1020];
int main() {
    freopen("paintbarn.in", "r", stdin);
    freopen("paintbarn.out", "w", stdout);
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        x1++;
        y1++;
        x2++;
        y2++;
        a[x1][y1]++;
        a[x1][y2]--;
        a[x2][y1]--;
        a[x2][y2]++;
    }
    for (int i = 1; i <= 1010; i++) {
        for (int j = 1; j <= 1010; j++) {
            a[i][j] += a[i][j - 1];
        }
    }
    for (int i = 1; i <= 1010; i++) {
        for (int j = 1; j <= 1010; j++) {
            a[i][j] += a[i - 1][j];
        }
    }
    int cnt = 0;
    for (int i = 1; i <= 1010; i++) {
        for (int j = 1; j <= 1010; j++) {
            if (a[i][j] == k) {
                cnt++;
            }
        }
    }
    cout << cnt << endl;
    return 0;
}

S3

#include <bits/stdc++.h>
using namespace std;
int n, m;
int f[200020];
int F(int x) {
    return f[x] != x ? f[x] = F(f[x]) : x;
}
void U(int x, int y) {
    f[F(x)] = F(y);
}
int main() {
    freopen("revegetate.in", "r", stdin);
    freopen("revegetate.out", "w", stdout);
    cin >> n >> m;
    for (int i = 0; i <= 2 * n; i++) {
        f[i] = i;
    }
    for (int i = 0; i < m; i++) {
        int x, y;
        char o;
        cin >> o >> x >> y;
        if (o == 'S') {
            U(x, y);
            U(x + n, y + n);
        } else {
            U(x + n, y);
            U(x, y + n);
        }
    }
    for (int i = 1; i <= n; i++) {
        if (F(i) == F(i + n)) {
            printf("0\n");
            return 0;
        }
    }
    int cnt = 0;
    for (int i = 1; i <= 2 * n; i++) {
        if (F(i) == i) {
            cnt++;
        }
    }
    cnt /= 2;
    printf("1");
    for (int i = 0; i < cnt; i++) {
        printf("0");
    }
    printf("\n");
    return 0;
}

Gold

G1

DFS序 + 树状数组

x到y路径上所有点的异或,就是
x到根节点所有点的异或 ^ y到根节点所有点的异或 ^ LCA(x, y)的点权。

#include <bits/stdc++.h>
using namespace std;
int n, q;
vector<int> a[100020];
int f[100020][20];
int d[100020];
int c[200020];
int w[100020];
int L[100020];
int R[100020];
int ss;
void change(int x, int y) {
    for (int i = x; i <= 2 * n; i += i & -i) {
        c[i] ^= y;
    }
}
int query(int x) {
    int re = 0;
    for (int i = x; i > 0; i -= i & -i) {
        re ^= c[i];
    }
    return re;
}
void dfs(int x, int y) {
    f[x][0] = y;
    d[x] = d[y] + 1;
    for (int i = 1; i < 20; i++) {
        f[x][i] = f[f[x][i - 1]][i - 1];
    }
    ss++;
    L[x] = ss;
    for (int i: a[x]) {
        if (i != y) {
            dfs(i, x);
        }
    }
    ss++;
    R[x] = ss;
}
int lca(int x, int y) {
    if (d[x] < d[y]) {
        swap(x, y);
    }
    int dd = d[x] - d[y];
    for (int i = 0; i < 20; i++) {
        if (dd >> i & 1) {
            x = f[x][i];
        }
    }
    if (x == y) {
        return x;
    }
    for (int i = 20 - 1; i >= 0; i--) {
        if (f[x][i] != f[y][i]) {
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
}
int main() {
    freopen("cowland.in", "r", stdin);
    freopen("cowland.out", "w", stdout);
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> w[i];
    }
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        a[x].push_back(y);
        a[y].push_back(x);
    }
    dfs(1, 0);
    for (int i = 1; i <= n; i++) {
        change(L[i], w[i]);
        change(R[i], w[i]);
    }
    for (int i = 0; i < q; i++) {
        int o, x, y;
        cin >> o >> x >> y;
        if (o == 1) {
            change(L[x], w[x] ^ y);
            change(R[x], w[x] ^ y);
            w[x] = y;
        } else {
            cout << (query(L[x]) ^ query(L[y]) ^ w[lca(x, y)]) << endl;
        }
    }
    return 0;
}

G2

二分,贪心。

#include <bits/stdc++.h>
using namespace std;
int n, a[100020];
vector<int> b[100020];
bool ok(int M) {
    int cnt = 0;
    int st = 0;
    for (int i = 0; i < M; i++) {
        b[i].clear();
    }
    int last = 0;
    for (int i = 1; i <= M; i++) {
        if (a[i] < last) {
            return false;
        }
        if (st == cnt) {
            b[cnt].push_back(a[i]);
            cnt++;
        } else if (a[i] > b[cnt - 1][0]) {
            b[cnt].push_back(a[i]);
            cnt++;
        } else {
            int left = st - 1;
            int right = cnt;
            while (left < right - 1) {
                int mid = (left + right) / 2;
                if (a[i] < b[mid][0]) {
                    right = mid;
                } else {
                    left = mid;
                }
            }
            if (a[i] < b[right].back()) {
                b[right].push_back(a[i]);
            } else {
                st = right;
                while (a[i] > b[right].back()) {
                    last = b[right].back();
                    b[right].pop_back();
                }
                b[right].push_back(a[i]);
            }
        }
//      for (int j = st; j <= cnt; j++) {
//          for (int k: b[j]) {
//              cout << k << ' ';
//          }
//          cout << endl;
//      }
    }
    return true;
}
int main() {
    freopen("dishes.in", "r", stdin);
    freopen("dishes.out", "w", stdout);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    int L = 0;
    int R = n + 1;
    while (L < R - 1) {
        int M = (L + R) / 2;
        if (ok(M)) {
            L = M;
        } else {
            R = M;
        }
    }
    cout << L << endl;
    return 0;
}

G3

注意选择的2个矩形不能有任何重叠的部分。
这样预处理出来前后几行的结果,前后几列的结果。枚举分割线即可。

#include <bits/stdc++.h>
using namespace std;
const int L = 200;
int n, k;
int a[220][220];
int b[220][220];
int c[220][220];
int cL[220];
int cR[220];
int rT[220];
int rB[220];
void gao(int a[220][220]) {
    for (int i = 1; i <= L; i++) {
        for (int j = 1; j <= L; j++) {
            a[i][j] += a[i][j - 1];
        }
    }
    for (int i = 1; i <= L; i++) {
        for (int j = 1; j <= L; j++) {
            a[i][j] += a[i - 1][j];
        }
    }
}
int main() {
    freopen("paintbarn.in", "r", stdin);
    freopen("paintbarn.out", "w", stdout);
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        x1++;
        y1++;
        x2++;
        y2++;
        a[x1][y1]++;
        a[x1][y2]--;
        a[x2][y1]--;
        a[x2][y2]++;
    }
    gao(a);
    int cnt = 0;
    for (int i = 1; i <= L; i++) {
        for (int j = 1; j <= L; j++) {
            if (a[i][j] == k) {
                b[i][j] = 1;
            }
            if (a[i][j] == k - 1) {
                c[i][j] = 1;
            }
        }
    }
    gao(b);
    gao(c);
    int ans = 0;
    for (int i1 = 0; i1 < L; i1++) {
        for (int i2 = i1 + 1; i2 <= L; i2++) {
            int tmp = 0;
            for (int j = 1; j <= L; j++) {
                int dd = 0;
                dd -= (b[i2][j] - b[i1][j]) - (b[i2][j - 1] - b[i1][j - 1]);
                dd += (c[i2][j] - c[i1][j]) - (c[i2][j - 1] - c[i1][j - 1]);
                tmp += dd;
                tmp = max(tmp, 0);
                cL[j] = max(cL[j], tmp);
            }
        }
    }
    for (int i1 = 0; i1 < L; i1++) {
        for (int i2 = i1 + 1; i2 <= L; i2++) {
            int tmp = 0;
            for (int j = L; j >= 1; j--) {
                int dd = 0;
                dd -= (b[i2][j] - b[i1][j]) - (b[i2][j - 1] - b[i1][j - 1]);
                dd += (c[i2][j] - c[i1][j]) - (c[i2][j - 1] - c[i1][j - 1]);
                tmp += dd;
                tmp = max(tmp, 0);
                cR[j] = max(cR[j], tmp);
            }
        }
    }
    for (int j1 = 0; j1 < L; j1++) {
        for (int j2 = j1 + 1; j2 <= L; j2++) {
            int tmp = 0;
            for (int i = 1; i <= L; i++) {
                int dd = 0;
                dd -= (b[i][j2] - b[i][j1]) - (b[i - 1][j2] - b[i - 1][j1]);
                dd += (c[i][j2] - c[i][j1]) - (c[i - 1][j2] - c[i - 1][j1]);
                tmp += dd;
                tmp = max(tmp, 0);
                rT[i] = max(rT[i], tmp);
            }
        }
    }
    for (int j1 = 0; j1 < L; j1++) {
        for (int j2 = j1 + 1; j2 <= L; j2++) {
            int tmp = 0;
            for (int i = L; i >= 1; i--) {
                int dd = 0;
                dd -= (b[i][j2] - b[i][j1]) - (b[i - 1][j2] - b[i - 1][j1]);
                dd += (c[i][j2] - c[i][j1]) - (c[i - 1][j2] - c[i - 1][j1]);
                tmp += dd;
                tmp = max(tmp, 0);
                rB[i] = max(rB[i], tmp);
            }
        }
    }
    int maxcL = 0;
    int maxrT = 0;
    for (int i = 1; i <= L + 1; i++) {
        maxcL = max(maxcL, cL[i-1]);
        maxrT = max(maxrT, rT[i-1]);
        ans = max(ans, maxcL + cR[i]);
        ans = max(ans, maxrT + rB[i]);
    }
    ans += b[L][L];
    cout << ans << endl;
    return 0;
}

Platinum

P1

注意到如果起点相同,那么随着终点向右移动,最优解是单峰的。

并且随着左端点从左向右移动,右端点的最优解是单调的。

所以就是双指针法。

注意到一个区间的答案是
(1-p1)(1-p2)..(1-pn) * (p1/(1-p1) + p2/(1-p2) + … + pn/(1-pn))

分别维护前后2部分,这样就可以支持在末尾追加一个概率,和删掉第一个概率。

疑似需要处理精度爆炸的问题(疑似需要取对数)

如果左端点是i,右端点的最优位置是best[i] (如果有多个最优位置,认为是最左的)
那么best[i]数组是单调增加的。

#include <bits/stdc++.h>
using namespace std;
int n;
long double p[1000020];
int main() {
    freopen("cowdate.in", "r", stdin);
    freopen("cowdate.out", "w", stdout);
    long double ans = 0;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
        p[i] /= 1e6;
        ans = max(ans, (long double)p[i]);
    }
    if (n <= 4000) {
        ans = 0;
        for (int i = 1; i <= n; i++) {
            long double f = 0;
            long double g = 0;
            for (int j = i; j <= n; j++) {
                f += log(1 - p[j]);
                g += p[j] / (1 - p[j]);
                ans = max(ans, exp(f) * g);
            }
        }
        printf("%d\n", (int)(1000000 * ans + 1e-6));
        return 0;
    }
    long double f = 0;
    long double g = 0;
    int j = 1;
    for (int i = 1; i <= n; i++) {
        while (j <= n && exp(f) * g < exp(f + log(1 - p[j])) * (g + p[j] / (1 - p[j]))) {
            f += log(1 - p[j]);
            g += p[j] / (1 - p[j]);
            ans = max(ans, exp(f) * g);
            j++;
        }
        f -= log(1 - p[i]);
        g -= p[i] / (1 - p[i]);
    }
    printf("%d\n", (int)(1000000 * ans + 0.13));
}

P2

首先不考虑y算一个全部的答案。

然后减去考虑y不合法的。

这是一个背包,对于每棵树需要预处理出来所有路径的长度。

(每个树选一个路径,加上(n-m) * x) < y 问方案数

然后最后还要乘上一个环排列(不同子树的顺序不定)

再除以2(顺时针和逆时针算作相同)

#include <bits/stdc++.h>
using namespace std;
const int mod = 1000000007;
vector<pair<int, int> > a[2520];
long long ans = 0;
long long cnt = 1;
long long sum;
int sz;
bool v[2520];
long long inv[2520];
long long f[2520];
long long g[2520];
int n, m, x, y;
int dfs(int x, int y) {
    v[x] = true;
    int re = 1;
    for (pair<int, int> i: a[x]) {
        if (i.first != y) {
            int tmp = dfs(i.first, x);
            re += tmp;
            sum += (long long)i.second * tmp * (sz - tmp);
        }
    }
    return re;
}
map<int, int> c;
map<int, int> gao(int x, int y) {
    v[x] = true;
    map<int, int> re;
    re[0] = 1;
    for (pair<int, int> i: a[x]) {
        if (i.first != y) {
            map<int, int> tmp = gao(i.first, x);
            for (pair<int, int> j: re) {
                for (pair<int, int> k: tmp) {
                    c[j.first + i.second + k.first] += j.second * k.second * 2;
                }
            }
            for (pair<int, int> k: tmp) {
                re[i.second + k.first] += k.second;
            }
        }
    }
    return re;
}
int main() {
    freopen("mooriokart.in", "r", stdin);
    freopen("mooriokart.out", "w", stdout);
    cin >> n >> m >> x >> y;
    inv[1] = 1;
    for (int i = 2; i <= n; i++) {
        inv[i] = inv[mod % i] * (mod - mod / i) % mod;
    }
    if ((n - m) * x <= y) {
        f[(n - m) * x] = 1;
    }

    for (int i = 0; i < m; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        a[x].push_back(make_pair(y, z));
        a[y].push_back(make_pair(x, z));
    }

    memset(v, 0, sizeof v);
    for (int i = 1; i <= n; i++) {
        if (!v[i]) {
            sz = dfs(i, 0);
            cnt = cnt * sz % mod * (sz - 1) % mod;
        }
    }

    memset(v, 0, sizeof v);
    for (int i = 1; i <= n; i++) {
        if (!v[i]) {
            sz = dfs(i, 0);
            sum = 0;
            dfs(i, 0);
            ans = (ans + cnt * inv[sz] % mod * inv[sz-1] % mod * sum % mod) % mod;
        }
    }

    ans *= 2;

    ans = (ans + cnt * (n - m) * x) % mod;

    memset(v, 0, sizeof v);
    for (int i = 1; i <= n; i++) {
        if (!v[i]) {
            c.clear();
            gao(i, 0);
            memset(g, 0, sizeof g);
//          for (pair<int, int> i: c) {
//              cout << i.first << ' ' << i.second << endl;
//          }
//          cout << endl;
            for (pair<int, int> i: c) {
                for (int j = i.first; j <= y; j++) {
                    g[j] = (g[j] + f[j - i.first] * i.second) % mod;
                }
            }
            swap(f, g);
        }
    }
//  for (int i = 0; i <= y; i++) {
//      cout << i << ' ' << f[i] << endl;
//  }
    for (int i = 0; i < y; i++) {
        ans = (ans - (long long)i * f[i] % mod + mod) % mod;
    }

    for (int i = 1; i < n - m; i++) {
        ans = ans * i % mod;
    }

    if (ans & 1) {
        ans += mod;
    }
    ans /= 2;
    cout << ans << endl;
    return 0;
}

P3

输入(0, 0)到(T, T)矩形内的n个点。

从(0, 0)到(T, T)只能向正方向走,希望经过最多的点(最长上升子序列)

如果从(x1, y1)走到(x2, y2)那么代价是(x2-x1) * (y2-y1)

问所有经过最多点的路径,权值最小的是多大?

T <= 1e6
n <= 2e5
n个点中,任意2个点,不会在同一行或同一列。

首先说说题目中的哪些条件有用,哪些没用吧。
T的范围基本没用。
任意2个点,不会在同一行或同一列,可以去掉,但是实现起来会麻烦很多。
最关键的是经过最多点的路径。

直接暴力是n^2的

然后假设求出了最长不下降子序列
每个点在最长不下降子序列中的位置是确定的。
动态规划中只需要考虑相邻两个位置之间的关系即可。

这个事情用暴力来做还是n^2的
怎么做更快呢?线段树分治

对于相邻两个位置i-1和i
假设i-1位置上的任意一个点,可以到i位置上的任意一个点,那么有一个非常简单的反向单调性。
(越靠右下的点,越会选到左上的点)

但是实际上,对于第i位置的点,不是i-1位置上的任意一个点都可以(可行的是一个区间)
这个区间是不包含的(这个条件没用)
对于第i-1层的点建一个线段树。

可以用这个线段树上的一些节点,拼出 可以转移到某点的区间。
这样对于线段树上每个节点,可以转移到一些点。
这个问题就转化为了
「假设i-1位置上的任意一个点,可以到i位置上的任意一个点,那么有一个非常简单的反向单调性。」

总时间复杂度大概是$O(n \log^2 n)$。

#include <bits/stdc++.h>
using namespace std;
int n;
pair<int, int> points[1000020];
int lastmin[1000020];
long long t;
vector<pair<int, int> > group[200020];
vector<long long> dp[200020];
vector<int> querys[800020];

void build(int x, int l, int r) {
    querys[x].clear();
    if (l == r) {
        return;
    }
    int mid = (l + r) / 2;
    build(x * 2, l, mid);
    build(x * 2 + 1, mid + 1, r);
}

void change(int x, int l, int r, int L, int R, int v) {
    if (L <= l && r <= R) {
        querys[x].push_back(v);
        return;
    }
    if (R < l || r < L) {
        return;
    }
    int mid = (l + r) / 2;
    change(x * 2, l, mid, L, R, v);
    change(x * 2 + 1, mid + 1, r, L, R, v);
}

void solve(const vector<int> &querys, int l, int r, int L, int R, int index) {
    if (l > r) {
        return;
    }
    int mid = (l + r) / 2;
    int j = querys[mid];
    long long best = 1e18;
    int pos = -1;
    for (int k = L; k <= R; k++) {
        int dx = (group[index][j].first - group[index - 1][k].first);
        int dy = (group[index][j].second - group[index - 1][k].second);
        if (dx > 0 && dy > 0) {
            long long tmp = dp[index - 1][k] + (long long)dx * dy;
            if (best > tmp) {
                best = tmp;
                pos = k;
            }
        }
    }
    assert(pos != -1);
    dp[index][j] = min(dp[index][j], best);
    solve(querys, l, mid - 1, pos, R, index);
    solve(querys, mid + 1, r, L, pos, index);
}

void query(int x, int l, int r, int index) {
    /*
    if (index == 2) {
        cerr << "tree " << x << ' ' << l << ' ' << r <<  ": ";
        for (int i: querys[x]) {
            cerr << i << ' ';
        }
        cerr << endl;
    }
    */
    solve(querys[x], 0, querys[x].size() - 1, l, r, index);
    if (l == r) {
        return;
    }
    int mid = (l + r) / 2;
    query(x * 2, l, mid, index);
    query(x * 2 + 1, mid + 1, r, index);
}

int main() {
    freopen("mowing.in", "r", stdin);
    freopen("mowing.out", "w", stdout);
    cin >> n >> t;
    for (int i = 1; i <= n; i++) {
        cin >> points[i].first >> points[i].second;
    }
    points[n + 1] = make_pair(t, t);
    sort(points, points + n + 2);
    for (int i = 0; i < n + 2; i++) {
        lastmin[i] = 1e9;
    }
    int length = 0;
    for (int i = 0; i < n + 2; i++) {
        int L = -1;
        int R = n + 2;
        while (L < R - 1) {
            int M = (L + R) / 2;
            if (lastmin[M] < points[i].second) {
                L = M;
            } else {
                R = M;
            }
        }
        lastmin[R] = points[i].second;
        group[R].push_back(points[i]);
        length = max(length, R);
    }
    dp[0].resize(1);
    dp[0][0] = 0;
    for (int i = 1; i <= length; i++) {
        dp[i].resize(group[i].size());
        build(1, 0, dp[i-1].size() - 1);
        for (int j = 0; j < group[i].size(); j++) {
            dp[i][j] = 1e18;
            int st = -1, ed = -1;
            {
                int L = -1, R = group[i-1].size();
                while (L < R - 1) {
                    int M = (L + R) / 2;
                    if (group[i-1][M].second > group[i][j].second) {
                        L = M;
                    } else {
                        R = M;
                    }
                }
                st = R;
            }
            {
                int L = -1, R = group[i-1].size();
                while (L < R - 1) {
                    int M = (L + R) / 2;
                    if (group[i-1][M].first > group[i][j].first) {
                        R = M;
                    } else {
                        L = M;
                    }
                }
                ed = L;
            }
            change(1, 0, group[i-1].size() - 1, st, ed, j);
        }
        query(1, 0, group[i-1].size() - 1, i);
        /*
        cerr << i << ": ";
        for (int j = 0; j < group[i].size(); j++) {
            cerr << dp[i][j] << ' ';
        }
        cerr << endl;
//      */
    }
    cout << dp[length][0] << endl;
    return 0;
}
wwwwodddd Uncategorized

Leave a Reply

Your email address will not be published. Required fields are marked *