ICPC 2019-2020 North-Western Russia Regional Contest 10/13

A

#include 
#include 
 
int main () {
    int a, b, n;
    scanf("%d%d%d", &a, &b, &n);
    auto ans = 1 + 2 * ((n - b + b - a - 1) / (b - a));
    printf("%d\n", ans);
}

B

x x x排序后,对于 s i n ( x ) sin(x) sin(x),DP找LIS就行(但是直接找5w长度的会飞,于是找2.5w长度的,但是要求最开始的 s i n ( x ) sin(x) sin(x)要大于0,那么可以根据 s i n ( x ) sin(x) sin(x)的性质,就可以翻回来,得到5w长度的。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
int main () {
    const int N = 25000;
    const int CNT = 8000000;
    const double EPS = 1e-12;
 
    using Pr = std::pair<double, int>;
 
    auto v = std::vector<Pr>(CNT);
    int x = ~0x7FFFFFFF;
    for (auto &p: v) {
        double s;
        while ((s = sin((double)x)) > -EPS)
            x += 2;
        p = { s, x };
        ++x;
    }
 
    assert(x < 0);
 
    auto ss = std::vector<Pr>();
    auto fa = std::vector<int>(CNT);
    ss.reserve(N);
    for (int i = 0; i < CNT; ++i) {
        auto it = std::lower_bound(
            std::begin(ss),
            std::end(ss),
            v[i],
            [](Pr const &a, Pr const &b) { return a.first < b.first; }
        );
        // fprintf(stderr, "> %d/%d\n", (int)(it - std::begin(ss)), (int)ss.size());
        fa[i] = (it != std::begin(ss) ? it[-1].second : -1);
        if (it == ss.end())
            ss.push_back({ v[i].first, i });
        else
            *it = { v[i].first, i };
        if (ss.size() == N)
            break;
    }
 
    int imx = ss.back().second;
    ss.clear();
    for (int i = imx; i != -1; i = fa[i])
        ss.push_back(v[i]);
    std::reverse(std::begin(ss), std::end(ss));
 
    for (int i = 1; i < N; ++i)
        assert(sin((long double)ss[i - 1].second) < sin((long double)ss[i].second));
 
    assert(ss.size() == N);
    auto chk = std::vector<int>();
 
    int n;
    scanf("%d", &n);
    if (n < N) {
        for (int i = 0; i < n; ++i)
            printf("%d\n", ss[i].second);
    } else {
        for (int i = 0; i < N; ++i) {
            printf("%d\n", ss[i].second);
            chk.push_back(ss[i].second);
        }
        n -= N;
        for (int i = 0; i < n; ++i) {
            printf("%d\n", -ss[ss.size() - 1 - i].second);
            chk.push_back(-ss[ss.size() - 1 - i].second);
        }
 
        for (int i = 1; i < (int)chk.size(); ++i) {
            assert(sin((long double)chk[i - 1]) < sin((long double)chk[i]));
            // fprintf(stderr, "%d\n", i);
            assert(chk[i - 1] < chk[i]);
        }
    }
 
    return 0;
}

C

考虑把一些边加上,然后欧拉路就行。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

using pii = pair<int, int>;

int const N = 105;
int const M = N * N;

set<pii> mp[N][N];
multiset<pii> mp2[N][N];
int du[N][N];
int a[N][N];
bool vis[N][N][4];
int n, m;

void link(int x, int y) {
	mp[x][y].insert({ x + 1, y + 1 });
	mp[x + 1][y].insert({ x, y + 1 });
	mp[x][y + 1].insert({ x + 1, y });
	mp[x + 1][y + 1].insert({ x, y });
	mp2[x][y].insert({ x + 1, y });
	mp2[x + 1][y].insert({ x, y });
	mp2[x][y + 1].insert({ x + 1, y + 1 });
	mp2[x + 1][y + 1].insert({ x, y + 1 });
}

bool in_map(pii const& p) {
	if (p.first < 0 || p.first > n)
		return 0;
	if (p.second < 0 || p.second > m)
		return 0;
	return 1;
}

void dfs(pii s, vector<pii>& ans, bool f) {
	if (f == 0) {
		for (; ;) {
			if (mp[s.first][s.second].size() == 0u)
				break;
			auto p = *mp[s.first][s.second].begin();
			mp[s.first][s.second].erase(p);
			mp[p.first][p.second].erase(s);
			//fprintf(stderr, "> %d %d -> %d %d\n", s.first, s.second, p.first, p.second);
			dfs(p, ans, f ^ 1);
			ans.push_back(p);
		}
	} else {
		auto& tmp = mp2[s.first][s.second];
		for (; ;) {
			if (tmp.size() == 0u)
				break;
			auto p = *tmp.begin();
			tmp.erase(tmp.find(p));
			auto tmp2 = mp2[p.first][p.second];
			tmp2.erase(tmp2.find(s));
			//fprintf(stderr, "> %d %d -> %d %d\n", s.first, s.second, p.first, p.second);
			dfs(p, ans, f ^ 1);
			ans.push_back(p);
		}
	}
}

int main() {
	scanf("%d%d", &m, &n);
	for (int i = 0; i < n; ++i) {
		static char s[N];
		scanf("%s", s);
		for (int j = 0; j < m; ++j) 
			if (s[j] == 'X') {
				a[i][j] = 1;
				link(i, j);
			}
	}
	pii s = { -1, -1 };
	for (int i = 0; i <= n; ++i)
		for (int j = 0; j <= m; ++j)
			if (mp2[i][j].size() && s == pii{ -1, -1 }) 
				s = { i, j };
	auto ans = vector<pii>();
	dfs(s, ans, 1);
	printf("%d\n", ans.size() - 1u);
	for (auto const& p : ans)
		printf("%d %d\n", p.second, p.first);
}

D

E

#include 
#include 
#include 
#include 
#include 
#include 
 
struct Graph {
    int n;
    std::vector<std::vector<int>> to;
    mutable std::vector<int> dis, fa;
 
    Graph (int n_): n(n_), to(n_), dis(n), fa(n) {}
 
    void adde (int a, int b) {
        to[a].push_back(b);
    }
 
    void bfs (int ibeg) const {
        const int INF = std::numeric_limits<int>::max();
        std::fill(std::begin(dis), std::end(dis), INF);
        std::fill(std::begin(fa), std::end(fa), 0);
 
        auto q = std::queue<int>();
        q.push(ibeg);
        dis[ibeg] = 0;
        fa[ibeg] = ibeg;
 
        while (!q.empty()) {
            int c = q.front();
            q.pop();
            for (int nxt: to[c])
                if (dis[nxt] == INF) {
                    dis[nxt] = dis[c] + 1;
                    fa[nxt] = c;
                    q.push(nxt);
                }
        }
    }
 
    int farthest (int ibeg, std::vector<int> const &enable) const {
        bfs(ibeg);
        return *std::max_element(
            std::begin(enable),
            std::end(enable),
            [&](int const &a, int const &b) { return dis[a] < dis[b]; }
        );
    }
 
    int mid (int ibeg, std::vector<int> const &enable) const {
        int c = farthest(ibeg, enable);
        int d = dis[c];
        if (d & 1)
            return -1;
        d /= 2;
        while (d--)
            c = fa[c];
        return c;
    }
 
    bool check (int ibeg, std::vector<int> const &enable) const {
        bfs(ibeg);
        for (int c: enable)
            if (dis[c] != dis[enable[0]])
                return false;
        return true;
    }
};
 
int main () {
    int n, k;
    scanf("%d%d", &n, &k);
 
    auto g = Graph(n);
    for (int i = 1; i < n; ++i) {
        int a, b;
        scanf("%d%d", &a, &b);
        --a, --b;
        g.adde(a, b);
        g.adde(b, a);
    }
 
    auto enable = std::vector<int>(k);
    int any;
    for (int i = 0; i < k; ++i) {
        scanf("%d", &enable[i]);
        any = --enable[i];
    }
 
    if (k == 1) {
        puts("YES\n1");
    } else {
        any = g.farthest(any, enable);
        // fprintf(stderr, "> %d\n", any);
        any = g.mid(any, enable);
        // fprintf(stderr, "> %d\n", any);
        if (any != -1 && g.check(any, enable)) {
            printf("YES\n%d\n", any + 1);
        } else {
            puts("NO");
        }
    }
 
    return 0;
}

F

G

H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
int const N = 200005;
 
struct ques {
    int v, id;
    int ans;
} q[N];
int qn;
 
bool cmp_v(ques const& x, ques const& y) {
    return x.v < y.v;
}
 
bool cmp_id(ques const& x, ques const& y) {
    return x.id < y.id;
}
 
int a[N];
int sum[N];
int n;
 
int get_r(int i, int lim) {
    int ret = upper_bound(sum + 1, sum + n + 1, sum[i] + lim) - sum;
    --ret;
    assert(sum[ret] <= sum[i] + lim);
    return ret;
}
 
int calc(int lim) {
    int ret = 0, l = 0;
    for (int i = 1; i <= n; ++i) {
        int r = get_r(l, lim);
        if (r <= l)
            return -1;
        ++ret;
        l = r;
        if (l == n)
            break;
    }
    return ret;
}
 
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    scanf("%d", &qn);
    for (int i = 1; i <= qn; ++i) {
        scanf("%d", &q[i].v);
        q[i].id = i;
    }
    sort(q + 1, q + qn + 1, cmp_v);
    int anss = 0;
    for (int i = 1; i <= qn; ++i) {
        if (i == 0 || q[i].v != q[i - 1].v)
            anss = calc(q[i].v);
        q[i].ans = anss;
    }
    sort(q + 1, q + qn + 1, cmp_id);
    for (int i = 1; i <= qn; ++i)
        if (q[i].ans >= 0)
            printf("%d\n", q[i].ans);
        else
            puts("Impossible");
}

I

#include 
using namespace std;
const int maxn=1005,INF=0x7FFFFFFF;
typedef pair <int,int> P;
int n,ansx,ansy,X[maxn],Y[maxn],H[maxn];
P jiao(P A,P B)
{
    int L=max(A.first,B.first),R=min(A.second,B.second);
    if (L>R) return P(INF,INF); else return P(L,R);
}
bool check(int key)
{
    P resX=P(-INF,INF),resY=P(-INF,INF);
    for (int i=1,del;i<=n;i++)
    {
        del=key-H[i];
        if (del<0) return false;
        resX=jiao(resX,P(X[i]-del,X[i]+del));
        resY=jiao(resY,P(Y[i]-del,Y[i]+del));
        if (resX.first==INF || resY.first==INF) return false;
    }
    int x=resX.first,y=resX.second,z=resY.first,w=resY.second;
    //printf(">>>>>> %d : %d %d %d %d\n",key,x,y,z,w);
    ansx=x;
    ansy=z;
    return true;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d%d",&X[i],&Y[i],&H[i]);
    int L=0,R=300000005,mid;
    while (L+1<R)
    {
        mid=L+R>>1;
        if (check(mid)) R=mid; else L=mid;
    }
    check(R);
    printf("%d %d %d",ansx,ansy,R);
    return 0;
}

J

#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
int const N = 505;
 
int a[N][N];
int ans[N][N];
int n;
 
int main() {
    scanf("%d", &n);
    static char s[N];
    for (int i = 1; i <= n; ++i) {
        scanf("%s", s + 1);
        for (int j = 1; j <= n; ++j)
            a[i][j] = s[j] - '0';
    }
    for (int k = n; k >= 1; --k) {
        for (int j = k + 1; j <= n; ++j) {
            int sum = 0;
            for (int i = k + 1; i < j; ++i)
                sum += ans[k][i] * a[i][j];
            sum %= 10;
            assert(sum == a[k][j] || (sum + 1) % 10 == a[k][j]);
            if (sum != a[k][j])
                ans[k][j] = 1;
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j)
            printf("%d", ans[i][j]);
        putchar('\n');
    }
}

K

最开始以为按顺序每个都直接让对应字母的矩形最大就好了,没想到WA on test40,然后搞出了反例,发现确实有些情况是不行的。然后random_shuffle了一下填充顺序就过了(emmmmm

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using Mat = std::vector<std::string>;
 
void solve_fill (int n, int m, Mat &mat, char ch) {
    using Pr = std::pair<int, int>;
 
    Pr p = { -1, -1 };
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            if (mat[i][j] == ch)
                p = { i, j };
    if (p.first == -1)
        return;
 
    using Mxh = std::vector<std::vector<int>>;
    Mxh mxh = Mxh(n, std::vector<int>(m, 0));
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < m; ++j)
            if (mat[i][j] == '.' || mat[i][j] == ch)
                mxh[i][j] = (i == 0 ? 0 : mxh[i - 1][j]) + 1;
 
    int mx = 0;
    std::pair<Pr, Pr> ans;
    for (int i = 0; i < n; ++i) {
        auto ss = std::stack<int>();
        for (int j = 0; j <= m; ++j) {
            int curmx = j == m ? 0 : mxh[i][j];
            while (!ss.empty() && mxh[i][ss.top()] >= curmx) {
                int h = mxh[i][ss.top()];
                ss.pop();
                // if (j > 0) {
                int prev = ss.empty() ? -1 : ss.top();
                int w = j - prev - 1;
                // if (ch == 'L' && i == 5 && j == 5) {
                //     fprintf(stderr, "ch=%c h=%d w=%d i=%d j=%d\n", ch, h, w, i, j);
                //     fprintf(stderr, "prev=%d mx=%d p.x=%d p.y=%d\n", prev, mx, p.first, p.second);
                // }
                if (prev < p.second && p.second < j && i - h < p.first && p.first <= i) {
                    if (h * w > mx) {
                        ans = { { i - h + 1, prev + 1 }, { i, j - 1 } };
                        mx = h * w;
                        // if (ch == 'L')
                        //     fprintf(stderr, "up ch=%c h=%d w=%d\n", ch, h, w);
                    }
                }
            }
            ss.push(j);
        }
    }
 
    // return;
 
    for (int i = ans.first.first; i <= ans.second.first; ++i)
        for (int j = ans.first.second; j <= ans.second.second; ++j)
            if (mat[i][j] == '.')
                mat[i][j] = ch - 'A' + 'a';
}
 
int main () {
    std::ios::sync_with_stdio(false);
 
    int n, m;
    std::cin >> n >> m;
 
    auto mat = Mat(n, std::string());
    for (auto &row: mat)
        std::cin >> row;
 
    solve_fill(n, m, mat, 'A');
 
    auto rng = std::mt19937(456328751);
    std::string ord = "BCDEFGHIJKLMNOPQRSTUVWXYZ";
    decltype(mat) mat2;
    for (;;) {
        std::shuffle(std::begin(ord), std::end(ord), rng);
        mat2 = mat;
        for (char ch: ord)
            solve_fill(n, m, mat2, ch);
 
        bool orz = false;
        for (int i = 0; i < n && !orz; ++i)
            for (int j = 0; j < m; ++j)
                if (mat2[i][j] == '.') {
                    orz = true;
                    break;
                }
        if (!orz)
            break;
    }
 
    for (auto &row: mat2)
        std::cout << row << '\n';
 
    return 0;
}
 

L

考虑如果直接枚举 i i i j j j开始的后缀 ( i < j ) (i < j) (i<j),那么这两个后缀构成的答案是什么。显然就是
j + L C P ( i , j ) − i j − i = 1 + L C P ( i , j ) j − i \frac{j + LCP(i, j) - i}{j-i} = 1 + \frac{LCP(i,j)}{j - i} jij+LCP(i,j)i=1+jiLCP(i,j)
那么考虑一下反串建SAM,因为LCA处可以统计答案,那么直接dsu on tree就行

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define SZ(x) ((int)(x).size())

int const N = 400005;

int sam_sz[N], par[N], mx[N], one[N];
bool tag[N];
int sam_cnt, sam_last;
map<int, int> ch[N];
int n;

string s;

void SAM_init() {
	sam_cnt = sam_last = 1;
}

int SAM_extend(int x, int pos) {
	int p, q, np, nq;
	p = sam_last;
	sam_last = np = ++sam_cnt;
	one[np] = pos;
	mx[np] = mx[p] + 1;
	sam_sz[np] = 1;
	tag[np] = 1;
	for (; p && ch[p].find(x) == ch[p].end(); p = par[p])
		ch[p][x] = np;
	if (p == 0)
		par[np] = 1;
	else {
		q = ch[p][x];
		if (mx[q] == mx[p] + 1)
			par[np] = q;
		else {
			nq = ++sam_cnt;
			mx[nq] = mx[p] + 1;
			ch[nq] = ch[q];
			par[nq] = par[q];
			one[nq] = one[q];
			par[q] = par[np] = nq;
			for (; ch[p][x] == q; p = par[p])
				ch[p][x] = nq;
		}
	}
	return sam_last;
}

vector<int> G[N];

void addedge(int x, int y) {
	G[x].emplace_back(y);
}

int sam_t[N], up[N];
void SAM_suffixTree() {
	static int c[257];
	memset(c, 0, sizeof(c));
	for (int i = 1; i <= sam_cnt; ++i)
		up[i] = s[one[i] - mx[par[i]]];
	for (int i = 1; i <= sam_cnt; ++i) 
		c[up[i]]++;
	for (int i = 1; i <= 256; ++i)
		c[i] += c[i - 1];
	for (int i = 1; i <= sam_cnt; ++i)
		sam_t[c[up[i]]--] = i;
	for (int i = 1; i <= sam_cnt; ++i) 
		addedge(par[sam_t[i]], sam_t[i]);
}

int siz[N], son[N];

void dfs(int x) {
	siz[x] = 1;
	for (auto y : G[x]) {
		dfs(y);
		siz[x] += siz[y];
		if (son[x] == 0 || siz[y] > siz[son[x]])
			son[x] = y;
	}
}

int fz = 0, fm = 1;

void update_ans(int i, int j, int A) {
	int tfz = A, tfm = j - i;
	if (1ll * fz * tfm < 1ll * tfz * fm) {
		fz = tfz;
		fm = tfm;
	}
}

void update(int p, set<int>& se, int A) {
	auto it = se.upper_bound(p);
	if (it != se.end()) 
		update_ans(p, *it, A);
	if (it != se.begin()) {
		--it;
		update_ans(*it, p, A);
	}
	se.insert(p);
}

void solve(int x, set<int>& se) {
	//cerr << "in : " << x << '\n';
	if (son[x]) 
		solve(son[x], se);
	if (tag[x])
		update(one[x], se, mx[x]);
	for (auto y : G[x]) 
		if (y != son[x]) {
			auto ts = set<int>();
			solve(y, ts);
			//cerr << "end : " << x << " -> " << y << '\n';
			for (auto t : ts)
				update(t, se, mx[x]);
		}
}
 
int main() {
	cin >> s;
	n = s.size();
	SAM_init();
	reverse(s.begin(), s.end());
	for (int i = 0; i < n; ++i)
		sam_last = SAM_extend(s[i] - 'a', i);
	SAM_suffixTree();
	dfs(1);

	auto ts = set<int>();
	solve(1, ts);

	fz += fm;
	int gcd = __gcd(fz, fm);
	fz /= gcd;
	fm /= gcd;
	cout << fz << '/' << fm << '\n';
}

M

#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
int const N = 2005;
 
int a[N];
int tot1[N], tot2[N];
 
int main() {
    int T;
    scanf("%d", &T);
    auto mp = map<int, int>();
    while (T--) {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        int ans = 0;
        for (int j = 1; j <= n; ++j) {
            mp.clear();
            int m1 = 0, m2 = 0;
            for (int i = 1; i < j; ++i)
                tot1[m1++] = a[j] - a[i];
            for (int k = j + 1; k <= n; ++k)
                tot2[m2++] = a[k] - a[j];
            sort(tot1, tot1 + m1);
            sort(tot2, tot2 + m2);
            int p = 0, num = 0;
            for (int i = 0; i < m1; ++i) {
                if (i == 0 || (tot1[i] != tot1[i - 1])) {
                    num = 0;
                    while (p < m2 && tot2[p] <= tot1[i]) {
                        if (tot2[p] == tot1[i])
                            ++num;
                        ++p;
                    }
                }
                ans += num;
            }
        }
        printf("%d\n", ans);
    }
}

你可能感兴趣的:(ACM补题)