Educational Codeforces Round 69 A, B, C, D, E, F

A - DIY Wooden Ladder

維護兩個點的堆

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
priority_queue<int, vector<int>, greater<int>> Q;
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        while (Q.size())
        {
            Q.pop();
        }
        // printf("...");
        Q.push(0);
        Q.push(0);
        int ret = 0;
        for (int i = 1; i <= n; i++)
        {
            int x;
            scanf("%d", &x);
            Q.push(x);
            x = Q.top();
            if (x != 0)
            {
                ret++;
            }
            Q.pop();
        }
        int r1 = Q.top();
        Q.pop();
        int r2 = Q.top();
        Q.pop();
        // printf("%d %d %d\n",r1,r2,ret);
        if (r1 == 0 || r2 == 0)
        {
            printf("%d\n", 0);
            continue;
        }
        printf("%d\n", min(ret, min(r1, r2) - 1));
    }
}

B - Pillars

線段樹裸題

#include <cstdio>
#include <algorithm>
using namespace std;
int a[200050];
int rr[200050];
int sgt[200050 << 2];
void build(int p, int l, int r)
{
    if (l == r)
    {
        sgt[p] = a[l];
        return;
    }
    int m = (l + r) >> 1;
    build(p << 1, l, m);
    build(p << 1 | 1, m + 1, r);
    sgt[p] = std::max(sgt[p << 1], sgt[p << 1 | 1]);
}
int maxx(int p, int l, int r, int L, int R)
{
    if (L <= l && r <= R)
    {
        return sgt[p];
    }
    int m = (l + r) >> 1, ret = 0;
    if (L <= m)
    {
        ret = max(ret, maxx(p << 1, l, m, L, R));
    }
    if (m < R)
    {
        ret = max(ret, maxx(p << 1 | 1, m + 1, r, L, R));
    }
    return ret;
}
void set(int p, int l, int r, int a, int x)
{
    if (l == r)
    {
        sgt[p] = x;
        return;
    }
    int m = (l + r) >> 1;
    if (a <= m)
    {
        set(p << 1, l, m, a, x);
    }
    else
    {
        set(p << 1 | 1, m + 1, r, a, x);
    }
    sgt[p] = max(sgt[p << 1], sgt[p << 1 | 1]);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        rr[a[i]] = i;
    }
    build(1, 1, n);
    a[rr[n]] = 0;
    set(1, 1, n, rr[n], 0);
    for (int i = n - 1; i >= 1; i--)
    {
        set(1, 1, n, rr[i], 0);
        int l = rr[i], r = rr[n];
        if (l > r)
        {
            swap(l, r);
        }
        if (maxx(1, 1, n, l, r) != 0)
        {
            puts("NO");
            return 0;
        }
    }
    puts("YES");
}

C - Array Splitting

要注意到是有序的

#include <cstdio>
#include <functional>
#include <algorithm>
using namespace std;
long long a[500000], b[500000];
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = a[i] - a[i - 1];
    }
    sort(b + 2, b + 1 + n, greater<long long>());
    long long ret = a[n] - a[1];
    for (int i = 2; i <= k; i++)
    {
        ret -= b[i];
    }
    printf("%lld\n", ret);
}

D - Yet Another Subarray Problem

記得初始化就能過了

#include <cstdio>
#include <algorithm>
using namespace std;
long long a[300005], k, dp[300005][12];
int main()
{
    int n, m;
    scanf("%d%d%lld", &n, &m, &k);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
    }
    long long ret = 0;
    for (int i = 1; i <= n; i++)
    {
        dp[i][0] = max(0ll, dp[i - 1][m - 1]) + a[i] - k;
        // if(dp[i][0] < 0) {
        //     dp[i][0] = max(a[i]-k,0ll);
        // }
        if (i != 1)
        {
            for (int j = 1; j < m; j++)
            {
                dp[i][j] = a[i] + dp[i - 1][j - 1];
                // if(dp[i][j] < 0) {
                //     dp[i][j] = 0;
                // }
                ret = max(dp[i][j], ret);
            }
        }
        else
        {
            for (int j = 1; j < m; j++)
            {
                dp[i][j] = -1ll << 60;
                // if(dp[i][j] < 0) {
                //     dp[i][j] = 0;
                // }
                ret = max(dp[i][j], ret);
            }
        }
        ret = max(dp[i][0], ret);
    }
    printf("%lld\n", ret);
}

E - Culture Code

線段樹維護區間信息

#include <cstdio>
#include <algorithm>
using namespace std;
struct wa
{
    int in, out;
} x[200050];
const int mod = 1e9 + 7;
int dp[200050 << 2], sum[200050 << 2];

void pushup(int p)
{
    if (dp[p << 1] < dp[p << 1 | 1])
    {
        dp[p] = dp[p << 1];
        sum[p] = sum[p << 1];
    }
    else if (dp[p << 1] > dp[p << 1 | 1])
    {

        dp[p] = dp[p << 1 | 1];
        sum[p] = sum[p << 1 | 1];
    }
    else
    {
        dp[p] = dp[p << 1];
        sum[p] = sum[p << 1] + sum[p << 1 | 1];
        if (sum[p] >= mod)
            sum[p] -= mod;
    }
}

void build(int p, int l, int r)
{
    if (l == r)
    {
        dp[p] = 0x3f3f3f3f;
        sum[p] = 0;
        // dp[p]=x[l].in;
        // sum[p]=1;
        return;
    }
    int m = (l + r) >> 1;
    build(p << 1, l, m);
    build(p << 1 | 1, m + 1, r);
    pushup(p);
}

void update(int p, int l, int r, int a, int dpp, int kk)
{
    if (l == r)
    {
        // if(dp[p]>dpp) {
        //     dp[p]=dpp;
        //     sum[p]=kk;
        // } else if (dp[p]==dpp){
        //     sum[p]+=kk;
        //     if(sum[p]>=mod) sum[p]-=mod;
        // }
        dp[p] = dpp;
        sum[p] = kk;
        return;
    }
    int m = (l + r) >> 1;
    if (a <= m)
    {
        update(p << 1, l, m, a, dpp, kk);
    }
    else
    {
        update(p << 1 | 1, m + 1, r, a, dpp, kk);
    }
    pushup(p);
}

void query(int p, int l, int r, int outer, int &dpp, int &kk)
{
    if (outer <= x[l].in)
    {
        if (dp[p] < dpp)
        {
            dpp = dp[p];
            kk = sum[p];
        }
        else if (dp[p] == dpp)
        {
            kk += sum[p];
            if (kk >= mod)
                kk -= mod;
        }
        return;
    }
    if (l == r)
    {
        return;
    }
    int m = (l + r) >> 1;
    if (outer <= x[m].in)
    {
        query(p << 1, l, m, outer, dpp, kk);
        query(p << 1 | 1, m + 1, r, outer, dpp, kk);
    }
    else
    {
        query(p << 1 | 1, m + 1, r, outer, dpp, kk);
    }
}
bool cmp(const wa &x, const wa &y)
{
    if (x.in == y.in)
    {
        return x.out < y.out;
    }
    return x.in < y.in;
}
int rm[200050];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", &x[i].out, &x[i].in);
    }
    sort(x + 1, x + 1 + n, cmp);
    build(1, 1, n);

    for (int i = n; i >= 1; i--)
    {
        int dpp = 0x3f3f3f3f, kk = 1;
        // printf("inout %d %d\n",x[i].in,x[i].out);
        query(1, 1, n, x[i].out, dpp, kk);
        if (dpp != 0x3f3f3f3f)
            update(1, 1, n, i, dpp + x[i].in - x[i].out, kk);
        else
            update(1, 1, n, i, x[i].in, 1);
        // printf("%d %d %d\n", dpp ,dpp+x[i].in-x[i].out,kk);
    }
    printf("%d\n", sum[1]);
}

F - Coloring Game

SG函數+SG定理+矩陣快速冪
SG很好想,快速冪粘個板子,然後光速TLE。
所以還是主要看板子,trick是預處理logmaxval\log maxval個矩陣,此後只需要累乘到答案向量上,這樣複雜度就從O((n+m)v3loga)\mathrm{O}((n+m)v^3\log a)降到了O(v3loga+(n+m)v2loga)\mathrm{O}(v^3\log a+(n+m)v^2\log a)
這個trick易見有好的優化:
Tv3loga&gt;(T+v)v2logaT&gt;vv1 Tv^3\log a &gt; (T+v)v^2\log a \Leftrightarrow T &gt; \frac{v}{v-1}
太強大了。

#include <cstdio>
#include <vector>
#include <utility>
#include <cstring>
#include <algorithm>
using namespace std;

using namespace std;

const int MOD = 998244353;
const long long MOD2 = 1ll * MOD * MOD;

typedef vector<int> vec;
typedef vector<vec> mat;

mat operator+(const mat &a, const mat &b)
{
	int n = a.size();
	mat c(n, vec(n));
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			int x = a[i][j] + b[i][j];
			x >= MOD ? x -= MOD : 0;
			c[i][j] = x;
		}
	}
	return c;
}
mat operator*(const mat &a, const mat &b)
{
	int n = a.size();
	mat c(n, vec(n));
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			long long x = 0;
			for (int k = 0; k < n; ++k)
			{
				x += 1ll * a[i][k] * b[k][j];
				x >= MOD2 ? x -= MOD2 : 0;
			}
			c[i][j] = x % MOD;
		}
	}
	return c;
}
vec operator*(const mat &a, const vec &b)
{
	int n = a.size();
	vec c(n);
	for (int i = 0; i < n; ++i)
	{
		long long x = 0;
		for (int j = 0; j < n; ++j)
		{
			x += 1ll * a[i][j] * b[j];
			x >= MOD2 ? x -= MOD2 : 0;
		}
		c[i] = x % MOD;
	}
	return c;
}

int len[1005];

vector<pair<int, int>> colored[1005];
int f[3][3];

mat color_matrix[3], full_matrix;
bool mex[4];
void build_matrix(int color)
{
	auto &matrix = color_matrix[color];
	matrix.resize(64, vec(64, 0));
	for (int i = 0; i < 64; i++)
	{
		int s3 = (i >> 4) & 3, s2 = (i >> 2) & 3, s1 = i & 3;
		memset(mex, 0, sizeof(mex));
		if (f[color][0])
			mex[s1] = 1;
		if (f[color][1])
			mex[s2] = 1;
		if (f[color][2])
			mex[s3] = 1;
		s3 = s2, s2 = s1;
		if (!mex[0])
			s1 = 0;
		else if (!mex[1])
			s1 = 1;
		else if (!mex[2])
			s1 = 2;
		else
			s1 = 3;
		int j = (s3 << 4) | (s2 << 2) | s1;
		matrix[j][i]++;
	}
}

mat pre[40];
long long dp[1005][5];
void init_full()
{
	pre[0] = full_matrix;
	for (int i = 1; i <= 30; i++)
	{
		pre[i] = pre[i - 1] * pre[i - 1];
	}
}
void powmul(int d, vec &b)
{
	for (int i = 0; i <= 30; i++)
	{
		if (d & 1)
			b = pre[i] * b;
		d >>= 1;
	}
	return;
}

void build_matrixs()
{
	for (int i = 0; i < 3; i++)
	{
		build_matrix(i);
	}
	full_matrix = color_matrix[0] + color_matrix[1] + color_matrix[2];
}

int main()
{

	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &len[i]);
	}

	int m;
	scanf("%d", &m);
	for (int i = 1; i <= m; i++)
	{
		int x, y, c;
		scanf("%d%d%d", &x, &y, &c);
		colored[x - 1].push_back({y - 1, c - 1});
	}
	for (int i = 0; i < n; i++)
	{
		sort(colored[i].begin(), colored[i].end());
	}

	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
		{
			scanf("%d", &f[i][j]);
		}

	build_matrixs();
	init_full();

	dp[0][0] = 1;

	for (int i = 0; i < n; i++)
	{
		vec ret(64, 0);
		ret[63] = 1;
		int lst = 0;
		for (auto col : colored[i])
		{
			powmul(col.first - lst, ret);
			ret = color_matrix[col.second] * ret;
			lst = col.first + 1;
		}
		powmul(len[i] - lst, ret);

		for (int k = 0; k <= 3; k++)
			for (int j = 0; j < 64; j++)
			{
				(dp[i + 1][k ^ (j & 3)] += (long long)dp[i][k] * ret[j] % MOD) %= MOD;
			}
	}
	printf("%lld\n", dp[n][0]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章